https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114610

            Bug ID: 114610
           Summary: -Wanalyzer-memory-leak reports often far too verbose
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: BenBE at geshi dot org
  Target Milestone: ---

When building htop with GCC14 + LTO + -fanalyzer, several potential
memory-leaks are reporte (related to xRealloc, cf. #114594).

One (of several reports) looks like the following:

```
XUtils.c: In function ‘xRealloc’:
XUtils.c:67:7: warning: leak of ‘realloc (ptr_4(D), size_1(D))’ [CWE-401]
[-Wanalyzer-malloc-leak]
   67 |    if (!data) {
      |       ^
  ‘Platform_actionSetIOPriority’: events 1-4
    |
    |linux/Platform.c:154:22:
    |  154 | static Htop_Reaction Platform_actionSetIOPriority(State* st) {
    |      |                      ^
    |      |                      |
    |      |                      (1) entry to ‘Platform_actionSetIOPriority’
    |  155 |    if (Settings_isReadonly())
    |      |       ~               
    |      |       |
    |      |       (2) following ‘false’ branch...
    |......
    |  158 |    const LinuxProcess* p = (const LinuxProcess*)
Panel_getSelected((Panel*)st->mainPanel);
    |      |                                                  ~                
          ~
    |      |                                                  |                
          |
    |      |                                                  |                
          (3) ...to here
    |      |                                                  (4) calling
‘Panel_getSelected’ from ‘Platform_actionSetIOPriority’
    |
    +--> ‘Panel_getSelected’: events 5-7
           |
           |Panel.c:158:9:
           |  158 | Object* Panel_getSelected(Panel* this) {
           |      |         ^
           |      |         |
           |      |         (5) entry to ‘Panel_getSelected’
           |  159 |    assert (this != NULL);
           |  160 |    if (Vector_size(this->items) > 0) {
           |      |       ~  
           |      |       |
           |      |       (6) following ‘true’ branch...
           |  161 |       return Vector_get(this->items, this->selected);
           |      |              ~
           |      |              |
           |      |              (7) ...to here
           |
    <------+
    |
  ‘Platform_actionSetIOPriority’: events 8-11
    |
    |linux/Platform.c:158:50:
    |  158 |    const LinuxProcess* p = (const LinuxProcess*)
Panel_getSelected((Panel*)st->mainPanel);
    |      |                                                  ^
    |      |                                                  |
    |      |                                                  (8) returning to
‘Platform_actionSetIOPriority’ from ‘Panel_getSelected’
    |  159 |    if (!p)
    |      |       ~                                           
    |      |       |
    |      |       (9) following ‘false’ branch (when ‘p_13’ is non-NULL)...
    |......
    |  162 |    IOPriority ioprio1 = p->ioPriority;
    |      |               ~                                   
    |      |               |
    |      |               (10) ...to here
    |  163 |    Panel* ioprioPanel = IOPriorityPanel_new(ioprio1);
    |      |                         ~                         
    |      |                         |
    |      |                         (11) calling ‘IOPriorityPanel_new’ from
‘Platform_actionSetIOPriority’
    |
    +--> ‘IOPriorityPanel_new’: events 12-13
           |
           |linux/IOPriorityPanel.c:22:8:
           |   22 | Panel* IOPriorityPanel_new(IOPriority currPrio) {
           |      |        ^
           |      |        |
           |      |        (12) entry to ‘IOPriorityPanel_new’
           |   23 |    Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem),
true, FunctionBar_newEnterEsc("Set    ", "Cancel "));
           |      |                  ~
           |      |                  |
           |      |                  (13) calling ‘FunctionBar_newEnterEsc’
from ‘IOPriorityPanel_new’
           |
           +--> ‘FunctionBar_newEnterEsc’: events 14-15
                  |
                  |FunctionBar.c:32:14:
                  |   32 | FunctionBar* FunctionBar_newEnterEsc(const char*
enter, const char* esc) {
                  |      |              ^
                  |      |              |
                  |      |              (14) entry to ‘FunctionBar_newEnterEsc’
                  |   33 |    const char* functions[] = {enter, esc, NULL};
                  |   34 |    return FunctionBar_new(functions,
FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
                  |      |           ~   
                  |      |           |
                  |      |           (15) calling ‘FunctionBar_new’ from
‘FunctionBar_newEnterEsc’
                  |
                  +--> ‘FunctionBar_new’: events 16-17
                         |
                         |   37 | FunctionBar* FunctionBar_new(const char*
const* functions, const char* const* keys, const int* events) {
                         |      |              ^
                         |      |              |
                         |      |              (16) entry to ‘FunctionBar_new’
                         |   38 |    FunctionBar* this = xCalloc(1,
sizeof(FunctionBar));
                         |      |                        ~
                         |      |                        |
                         |      |                        (17) calling ‘xCalloc’
from ‘FunctionBar_new’
                         |
                         +--> ‘xCalloc’: events 18-22
                                |
                                |XUtils.c:51:7:
                                |   51 | void* xCalloc(size_t nmemb, size_t
size) {
                                |      |       ^
                                |      |       |
                                |      |       (18) entry to ‘xCalloc’
                                |......
                                |   54 |    if (SIZE_MAX / nmemb < size) {
                                |      |       ~
                                |      |       |
                                |      |       (19) following ‘false’ branch...
                                |......
                                |   57 |    void* data = calloc(nmemb, size);
                                |      |                 ~
                                |      |                 |
                                |      |                 (20) ...to here
                                |   58 |    if (!data) {
                                |      |       ~
                                |      |       |
                                |      |       (21) following ‘false’ branch
(when ‘data_7’ is non-NULL)...
                                |......
                                |   61 |    return data;
                                |      |           ~
                                |      |           |
                                |      |           (22) ...to here
                                |
                         <------+
                         |
                       ‘FunctionBar_new’: events 23-24
                         |
                         |FunctionBar.c:38:24:
                         |   38 |    FunctionBar* this = xCalloc(1,
sizeof(FunctionBar));
                         |      |                        ^
                         |      |                        |
                         |      |                        (23) returning to
‘FunctionBar_new’ from ‘xCalloc’
                         |   39 |    this->functions = xCalloc(16,
sizeof(char*));
                         |      |                      ~  
                         |      |                      |
                         |      |                      (24) calling ‘xCalloc’
from ‘FunctionBar_new’
                         |
                         +--> ‘xCalloc’: events 25-29
                                |
                                |XUtils.c:51:7:
                                |   51 | void* xCalloc(size_t nmemb, size_t
size) {
                                |      |       ^
                                |      |       |
                                |      |       (25) entry to ‘xCalloc’
                                |......
                                |   54 |    if (SIZE_MAX / nmemb < size) {
                                |      |       ~
                                |      |       |
                                |      |       (26) following ‘false’ branch...
                                |......
                                |   57 |    void* data = calloc(nmemb, size);
                                |      |                 ~
                                |      |                 |
                                |      |                 (27) ...to here
                                |   58 |    if (!data) {
                                |      |       ~
                                |      |       |
                                |      |       (28) following ‘false’ branch
(when ‘data_7’ is non-NULL)...
                                |......
                                |   61 |    return data;
                                |      |           ~
                                |      |           |
                                |      |           (29) ...to here
                                |
                         <------+
                         |
                       ‘FunctionBar_new’: events 30-35
                         |
                         |FunctionBar.c:39:22:
                         |   39 |    this->functions = xCalloc(16,
sizeof(char*));
                         |      |                      ^
                         |      |                      |
                         |      |                      (30) returning to
‘FunctionBar_new’ from ‘xCalloc’
                         |   40 |    if (!functions) {
                         |      |       ~               
                         |      |       |
                         |      |       (31) following ‘false’ branch (when
‘functions_37(D)’ is non-NULL)...
                         |......
                         |   43 |    for (int i = 0; i < 15 && functions[i];
i++) {
                         |      |    ~                      ~
                         |      |    |                      |
                         |      |    |                      (33) following
‘true’ branch...
                         |      |    (32) ...to here
                         |   44 |       this->functions[i] =
xStrdup(functions[i]);
                         |      |                      ~     ~
                         |      |                      |     |
                         |      |                      |     (35) calling
‘xStrdup’ from ‘FunctionBar_new’
                         |      |                      (34) ...to here
                         |
                         +--> ‘xStrdup’: events 36-38
                                |
                                |XUtils.c:253:7:
                                |  253 | char* xStrdup(const char* str) {
                                |      |       ^
                                |      |       |
                                |      |       (36) entry to ‘xStrdup’
                                |  254 |    char* data = strdup(str);
                                |  255 |    if (!data) {
                                |      |       ~
                                |      |       |
                                |      |       (37) following ‘false’ branch
(when ‘data_4’ is non-NULL)...
                                |......
                                |  258 |    return data;
                                |      |           ~
                                |      |           |
                                |      |           (38) ...to here
                                |
                         <------+
                         |
                       ‘FunctionBar_new’: events 39-42
                         |
                         |FunctionBar.c:44:28:
                         |   43 |    for (int i = 0; i < 15 && functions[i];
i++) {
                         |      |                           ~ 
                         |      |                           |
                         |      |                           (40) following
‘true’ branch...
                         |   44 |       this->functions[i] =
xStrdup(functions[i]);
                         |      |                      ~     ^
                         |      |                      |     |
                         |      |                      |     (39) returning to
‘FunctionBar_new’ from ‘xStrdup’
                         |      |                      |     (42) calling
‘xStrdup’ from ‘FunctionBar_new’
                         |      |                      (41) ...to here
                         |
                         +--> ‘xStrdup’: events 43-45
                                |
                                |XUtils.c:253:7:
                                |  253 | char* xStrdup(const char* str) {
                                |      |       ^
                                |      |       |
                                |      |       (43) entry to ‘xStrdup’
                                |  254 |    char* data = strdup(str);
                                |  255 |    if (!data) {
                                |      |       ~
                                |      |       |
                                |      |       (44) following ‘false’ branch
(when ‘data_4’ is non-NULL)...
                                |......
                                |  258 |    return data;
                                |      |           ~
                                |      |           |
                                |      |           (45) ...to here
                                |
                         <------+
                         |
                       ‘FunctionBar_new’: events 46-52
                         |
                         |FunctionBar.c:44:28:
                         |   43 |    for (int i = 0; i < 15 && functions[i];
i++) {
                         |      |                           ~           ~
                         |      |                           |           |
                         |      |                           |           (48)
...to here
                         |      |                           (47) following
‘true’ branch (when ‘i_27 != 15’)...
                         |      |                           (49) following
‘false’ branch...
                         |   44 |       this->functions[i] =
xStrdup(functions[i]);
                         |      |                            ^
                         |      |                            |
                         |      |                            (46) returning to
‘FunctionBar_new’ from ‘xStrdup’
                         |   45 |    }
                         |   46 |    if (keys && events) {
                         |      |       ~~                    
                         |      |       ||
                         |      |       |(50) ...to here
                         |      |       (51) following ‘false’ branch...
                         |......
                         |   58 |       this->staticData = true;
                         |      |                        ~    
                         |      |                        |
                         |      |                        (52) ...to here
                         |
                  <------+
                  |
                ‘FunctionBar_newEnterEsc’: event 53
                  |
                  |   34 |    return FunctionBar_new(functions,
FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents);
                  |      |           ^
                  |      |           |
                  |      |           (53) returning to
‘FunctionBar_newEnterEsc’ from ‘FunctionBar_new’
                  |
           <------+
           |
         ‘IOPriorityPanel_new’: events 54-55
           |
           |linux/IOPriorityPanel.c:23:18:
           |   23 |    Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem),
true, FunctionBar_newEnterEsc("Set    ", "Cancel "));
           |      |                  ^
           |      |                  |
           |      |                  (54) returning to ‘IOPriorityPanel_new’
from ‘FunctionBar_newEnterEsc’
           |      |                  (55) calling ‘Panel_new’ from
‘IOPriorityPanel_new’
           |
           +--> ‘Panel_new’: events 56-57
                  |
                  |Panel.c:35:8:
                  |   35 | Panel* Panel_new(int x, int y, int w, int h, const
ObjectClass* type, bool owner, FunctionBar* fuBar) {
                  |      |        ^
                  |      |        |
                  |      |        (56) entry to ‘Panel_new’
                  |   36 |    Panel* this;
                  |   37 |    this = xMalloc(sizeof(Panel));
                  |      |           ~
                  |      |           |
                  |      |           (57) calling ‘xMalloc’ from ‘Panel_new’
                  |
                  +--> ‘xMalloc’: events 58-60
                         |
                         |XUtils.c:33:7:
                         |   33 | void* xMalloc(size_t size) {
                         |      |       ^
                         |      |       |
                         |      |       (58) entry to ‘xMalloc’
                         |......
                         |   36 |    if (!data) {
                         |      |       ~
                         |      |       |
                         |      |       (59) following ‘false’ branch (when
‘data_4’ is non-NULL)...
                         |......
                         |   39 |    return data;
                         |      |           ~
                         |      |           |
                         |      |           (60) ...to here
                         |
                  <------+
                  |
                ‘Panel_new’: events 61-62
                  |
                  |Panel.c:37:11:
                  |   37 |    this = xMalloc(sizeof(Panel));
                  |      |           ^
                  |      |           |
                  |      |           (61) returning to ‘Panel_new’ from
‘xMalloc’
                  |   38 |    Object_setClass(this, Class(Panel));
                  |   39 |    Panel_init(this, x, y, w, h, type, owner, fuBar);
                  |      |    ~       
                  |      |    |
                  |      |    (62) calling ‘Panel_init’ from ‘Panel_new’
                  |
                  +--> ‘Panel_init’: events 63-64
                         |
                         |   49 | void Panel_init(Panel* this, int x, int y,
int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
                         |      |      ^
                         |      |      |
                         |      |      (63) entry to ‘Panel_init’
                         |......
                         |   57 |    this->items = Vector_new(type, owner,
DEFAULT_SIZE);
                         |      |                  ~
                         |      |                  |
                         |      |                  (64) calling ‘Vector_new’
from ‘Panel_init’
                         |
                         +--> ‘Vector_new’: events 65-66
                                |
                                |Vector.c:19:9:
                                |   19 | Vector* Vector_new(const ObjectClass*
type, bool owner, int size) {
                                |      |         ^
                                |      |         |
                                |      |         (65) entry to ‘Vector_new’
                                |......
                                |   22 |    if (size == DEFAULT_SIZE) {
                                |      |       ~  
                                |      |       |
                                |      |       (66) following ‘true’ branch
(when ‘size_4(D) == -1’)...
                                |
                              ‘Vector_new’: event 67
                                |
                                |lto1:
                                | (67): ...to here
                                |
                              ‘Vector_new’: event 68
                                |
                                |   27 |    this = xMalloc(sizeof(Vector));
                                |      |           ^
                                |      |           |
                                |      |           (68) calling ‘xMalloc’ from
‘Vector_new’
                                |
                                +--> ‘xMalloc’: events 69-71
                                       |
                                       |XUtils.c:33:7:
                                       |   33 | void* xMalloc(size_t size) {
                                       |      |       ^
                                       |      |       |
                                       |      |       (69) entry to ‘xMalloc’
                                       |......
                                       |   36 |    if (!data) {
                                       |      |       ~
                                       |      |       |
                                       |      |       (70) following ‘false’
branch (when ‘data_4’ is non-NULL)...
                                       |......
                                       |   39 |    return data;
                                       |      |           ~
                                       |      |           |
                                       |      |           (71) ...to here
                                       |
                                <------+
                                |
                              ‘Vector_new’: events 72-73
                                |
                                |Vector.c:27:11:
                                |   27 |    this = xMalloc(sizeof(Vector));
                                |      |           ^
                                |      |           |
                                |      |           (72) returning to
‘Vector_new’ from ‘xMalloc’
                                |......
                                |   30 |       .array = xCalloc(size,
sizeof(Object*)),
                                |      |                ~
                                |      |                |
                                |      |                (73) calling ‘xCalloc’
from ‘Vector_new’
                                |
                                +--> ‘xCalloc’: events 74-78
                                       |
                                       |XUtils.c:51:7:
                                       |   51 | void* xCalloc(size_t nmemb,
size_t size) {
                                       |      |       ^
                                       |      |       |
                                       |      |       (74) entry to ‘xCalloc’
                                       |......
                                       |   54 |    if (SIZE_MAX / nmemb < size)
{
                                       |      |       ~
                                       |      |       |
                                       |      |       (75) following ‘false’
branch...
                                       |......
                                       |   57 |    void* data = calloc(nmemb,
size);
                                       |      |                 ~
                                       |      |                 |
                                       |      |                 (76) ...to here
                                       |   58 |    if (!data) {
                                       |      |       ~
                                       |      |       |
                                       |      |       (77) following ‘false’
branch (when ‘data_7’ is non-NULL)...
                                       |......
                                       |   61 |    return data;
                                       |      |           ~
                                       |      |           |
                                       |      |           (78) ...to here
                                       |
                                <------+
                                |
                              ‘Vector_new’: event 79
                                |
                                |Vector.c:30:16:
                                |   30 |       .array = xCalloc(size,
sizeof(Object*)),
                                |      |                ^
                                |      |                |
                                |      |                (79) returning to
‘Vector_new’ from ‘xCalloc’
                                |
                         <------+
                         |
                       ‘Panel_init’: event 80
                         |
                         |Panel.c:57:18:
                         |   57 |    this->items = Vector_new(type, owner,
DEFAULT_SIZE);
                         |      |                  ^
                         |      |                  |
                         |      |                  (80) returning to
‘Panel_init’ from ‘Vector_new’
                         |
                  <------+
                  |
                ‘Panel_new’: event 81
                  |
                  |   39 |    Panel_init(this, x, y, w, h, type, owner, fuBar);
                  |      |    ^
                  |      |    |
                  |      |    (81) returning to ‘Panel_new’ from ‘Panel_init’
                  |
           <------+
           |
         ‘IOPriorityPanel_new’: events 82-83
           |
           |linux/IOPriorityPanel.c:23:18:
           |   23 |    Panel* this = Panel_new(1, 1, 1, 1, Class(ListItem),
true, FunctionBar_newEnterEsc("Set    ", "Cancel "));
           |      |                  ^
           |      |                  |
           |      |                  (82) returning to ‘IOPriorityPanel_new’
from ‘Panel_new’
           |   24 | 
           |   25 |    Panel_setHeader(this, "IO Priority:");
           |      |    ~              
           |      |    |
           |      |    (83) calling ‘Panel_setHeader’ from
‘IOPriorityPanel_new’
           |
           +--> ‘Panel_setHeader’: events 84-85
                  |
                  |Panel.c:89:13:
                  |   89 | inline void Panel_setHeader(Panel* this, const char*
header) {
                  |      |             ^
                  |      |             |
                  |      |             (84) entry to ‘Panel_setHeader’
                  |   90 |    RichString_writeWide(&(this->header),
CRT_colors[PANEL_HEADER_FOCUS], header);
                  |      |    ~         
                  |      |    |
                  |      |    (85) calling ‘RichString_writeWide’ from
‘Panel_setHeader’
                  |
                  +--> ‘RichString_writeWide’: events 86-87
                         |
                         |RichString.c:242:5:
                         |  242 | int RichString_writeWide(RichString* this,
int attrs, const char* data) {
                         |      |     ^
                         |      |     |
                         |      |     (86) entry to ‘RichString_writeWide’
                         |  243 |    return RichString_writeFromWide(this,
attrs, data, 0, strlen(data));
                         |      |           ~
                         |      |           |
                         |      |           (87) calling
‘RichString_writeFromWide’ from ‘RichString_writeWide’
                         |
                         +--> ‘RichString_writeFromWide’: events 88-89
                                |
                                |   90 | static inline int
RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int
from, int len) {
                                |      |                   ^
                                |      |                   |
                                |      |                   (88) entry to
‘RichString_writeFromWide’
                                |   91 |    wchar_t data[len];
                                |   92 |    len = mbstowcs_nonfatal(data,
data_c, len);
                                |      |          ~         
                                |      |          |
                                |      |          (89) calling
‘mbstowcs_nonfatal’ from ‘RichString_writeFromWide’
                                |
                                +--> ‘mbstowcs_nonfatal’: events 90-100
                                       |
                                       |   57 | static size_t
mbstowcs_nonfatal(wchar_t* dest, const char* src, size_t n) {
                                       |      |               ^
                                       |      |               |
                                       |      |               (90) entry to
‘mbstowcs_nonfatal’
                                       |......
                                       |   62 |    while (n > 0) {
                                       |      |             ~  
                                       |      |             |
                                       |      |             (91) following
‘true’ branch (when ‘n_5 != 0’)...
                                       |      |             (95) following
‘true’ branch (when ‘n_5 != 0’)...
                                       |      |             (99) following
‘true’ branch (when ‘n_5 != 0’)...
                                       |   63 |       size_t ret =
mbrtowc(dest, src, n, &ps);
                                       |      |                    ~
                                       |      |                    |
                                       |      |                    (92) ...to
here
                                       |      |                    (96) ...to
here
                                       |      |                    (100) ...to
here
                                       |   64 |       if (ret == (size_t)-1 ||
ret == (size_t)-2) {
                                       |   65 |          if (!broken) {
                                       |      |             ~  
                                       |      |             |
                                       |      |             (93) following
‘false’ branch (when ‘broken_8 == 0’)...
                                       |      |             (97) following
‘true’ branch (when ‘broken_8 != 0’)...
                                       |   66 |             broken = true;
                                       |   67 |             *dest++ =
L'\xFFFD';
                                       |      |                  ~
                                       |      |                  |
                                       |      |                  (94) ...to
here
                                       |......
                                       |   70 |          src++;
                                       |      |             ~  
                                       |      |             |
                                       |      |             (98) ...to here
                                       |
                                <------+
                                |
                              ‘RichString_writeFromWide’: event 101
                                |
                                |   92 |    len = mbstowcs_nonfatal(data,
data_c, len);
                                |      |          ^
                                |      |          |
                                |      |          (101) returning to
‘RichString_writeFromWide’ from ‘mbstowcs_nonfatal’
                                |
                         <------+
                         |
                       ‘RichString_writeWide’: event 102
                         |
                         |  243 |    return RichString_writeFromWide(this,
attrs, data, 0, strlen(data));
                         |      |           ^
                         |      |           |
                         |      |           (102) returning to
‘RichString_writeWide’ from ‘RichString_writeFromWide’
                         |
                  <------+
                  |
                ‘Panel_setHeader’: event 103
                  |
                  |Panel.c:90:4:
                  |   90 |    RichString_writeWide(&(this->header),
CRT_colors[PANEL_HEADER_FOCUS], header);
                  |      |    ^
                  |      |    |
                  |      |    (103) returning to ‘Panel_setHeader’ from
‘RichString_writeWide’
                  |
           <------+
           |
         ‘IOPriorityPanel_new’: events 104-105
           |
           |linux/IOPriorityPanel.c:25:4:
           |   25 |    Panel_setHeader(this, "IO Priority:");
           |      |    ^
           |      |    |
           |      |    (104) returning to ‘IOPriorityPanel_new’ from
‘Panel_setHeader’
           |   26 |    Panel_add(this, (Object*) ListItem_new("None (based on
nice)", IOPriority_None));
           |      |                              ~
           |      |                              |
           |      |                              (105) calling ‘ListItem_new’
from ‘IOPriorityPanel_new’
           |
           +--> ‘ListItem_new’: events 106-107
                  |
                  |ListItem.c:47:11:
                  |   47 | ListItem* ListItem_new(const char* value, int key) {
                  |      |           ^
                  |      |           |
                  |      |           (106) entry to ‘ListItem_new’
                  |   48 |    ListItem* this = AllocThis(ListItem);
                  |      |                     ~
                  |      |                     |
                  |      |                     (107) calling ‘xMalloc’ from
‘ListItem_new’
                  |
                  +--> ‘xMalloc’: events 108-110
                         |
                         |XUtils.c:33:7:
                         |   33 | void* xMalloc(size_t size) {
                         |      |       ^
                         |      |       |
                         |      |       (108) entry to ‘xMalloc’
                         |......
                         |   36 |    if (!data) {
                         |      |       ~
                         |      |       |
                         |      |       (109) following ‘false’ branch (when
‘data_4’ is non-NULL)...
                         |......
                         |   39 |    return data;
                         |      |           ~
                         |      |           |
                         |      |           (110) ...to here
                         |
                  <------+
                  |
                ‘ListItem_new’: events 111-112
                  |
                  |ListItem.c:48:21:
                  |   48 |    ListItem* this = AllocThis(ListItem);
                  |      |                     ^
                  |      |                     |
                  |      |                     (111) returning to
‘ListItem_new’ from ‘xMalloc’
                  |   49 |    ListItem_init(this, value, key);
                  |      |    ~                 
                  |      |    |
                  |      |    (112) inlined call to ‘ListItem_init’ from
‘ListItem_new’
                  |
                  +--> ‘ListItem_init’: event 113
                         |
                         |   42 |    this->value = xStrdup(value);
                         |      |                  ^
                         |      |                  |
                         |      |                  (113) calling ‘xStrdup’ from
‘ListItem_new’
                         |
                       ‘xStrdup’: events 114-116
                         |
                         |XUtils.c:253:7:
                         |  253 | char* xStrdup(const char* str) {
                         |      |       ^
                         |      |       |
                         |      |       (114) entry to ‘xStrdup’
                         |  254 |    char* data = strdup(str);
                         |  255 |    if (!data) {
                         |      |       ~
                         |      |       |
                         |      |       (115) following ‘false’ branch (when
‘data_4’ is non-NULL)...
                         |......
                         |  258 |    return data;
                         |      |           ~
                         |      |           |
                         |      |           (116) ...to here
                         |
                  <------+
                  |
                ‘ListItem_new’: event 117
                  |
                  |ListItem.c:49:4:
                  |   49 |    ListItem_init(this, value, key);
                  |      |    ^
                  |      |    |
                  |      |    (117) inlined call to ‘ListItem_init’ from
‘ListItem_new’
                  |
                  +--> ‘ListItem_init’: event 118
                         |
                         |   42 |    this->value = xStrdup(value);
                         |      |                  ^
                         |      |                  |
                         |      |                  (118) returning to
‘ListItem_new’ from ‘xStrdup’
                         |
           <-------------+
           |
         ‘IOPriorityPanel_new’: events 119-120
           |
           |linux/IOPriorityPanel.c:26:30:
           |   26 |    Panel_add(this, (Object*) ListItem_new("None (based on
nice)", IOPriority_None));
           |      |                              ^
           |      |                              |
           |      |                              (119) returning to
‘IOPriorityPanel_new’ from ‘ListItem_new’
           |......
           |   49 |    Panel_add(this, (Object*) ListItem_new("Idle",
IOPriority_Idle));
           |      |                              ~
           |      |                              |
           |      |                              (120) calling ‘ListItem_new’
from ‘IOPriorityPanel_new’
           |
           +--> ‘ListItem_new’: events 121-122
                  |
                  |ListItem.c:47:11:
                  |   47 | ListItem* ListItem_new(const char* value, int key) {
                  |      |           ^
                  |      |           |
                  |      |           (121) entry to ‘ListItem_new’
                  |   48 |    ListItem* this = AllocThis(ListItem);
                  |      |                     ~
                  |      |                     |
                  |      |                     (122) calling ‘xMalloc’ from
‘ListItem_new’
                  |
                  +--> ‘xMalloc’: events 123-125
                         |
                         |XUtils.c:33:7:
                         |   33 | void* xMalloc(size_t size) {
                         |      |       ^
                         |      |       |
                         |      |       (123) entry to ‘xMalloc’
                         |......
                         |   36 |    if (!data) {
                         |      |       ~
                         |      |       |
                         |      |       (124) following ‘false’ branch (when
‘data_4’ is non-NULL)...
                         |......
                         |   39 |    return data;
                         |      |           ~
                         |      |           |
                         |      |           (125) ...to here
                         |
                  <------+
                  |
                ‘ListItem_new’: events 126-127
                  |
                  |ListItem.c:48:21:
                  |   48 |    ListItem* this = AllocThis(ListItem);
                  |      |                     ^
                  |      |                     |
                  |      |                     (126) returning to
‘ListItem_new’ from ‘xMalloc’
                  |   49 |    ListItem_init(this, value, key);
                  |      |    ~                 
                  |      |    |
                  |      |    (127) inlined call to ‘ListItem_init’ from
‘ListItem_new’
                  |
                  +--> ‘ListItem_init’: event 128
                         |
                         |   42 |    this->value = xStrdup(value);
                         |      |                  ^
                         |      |                  |
                         |      |                  (128) calling ‘xStrdup’ from
‘ListItem_new’
                         |
                       ‘xStrdup’: events 129-131
                         |
                         |XUtils.c:253:7:
                         |  253 | char* xStrdup(const char* str) {
                         |      |       ^
                         |      |       |
                         |      |       (129) entry to ‘xStrdup’
                         |  254 |    char* data = strdup(str);
                         |  255 |    if (!data) {
                         |      |       ~
                         |      |       |
                         |      |       (130) following ‘false’ branch (when
‘data_4’ is non-NULL)...
                         |......
                         |  258 |    return data;
                         |      |           ~
                         |      |           |
                         |      |           (131) ...to here
                         |
                  <------+
                  |
                ‘ListItem_new’: event 132
                  |
                  |ListItem.c:49:4:
                  |   49 |    ListItem_init(this, value, key);
                  |      |    ^
                  |      |    |
                  |      |    (132) inlined call to ‘ListItem_init’ from
‘ListItem_new’
                  |
                  +--> ‘ListItem_init’: event 133
                         |
                         |   42 |    this->value = xStrdup(value);
                         |      |                  ^
                         |      |                  |
                         |      |                  (133) returning to
‘ListItem_new’ from ‘xStrdup’
                         |
           <-------------+
           |
         ‘IOPriorityPanel_new’: events 134-135
           |
           |linux/IOPriorityPanel.c:49:30:
           |   49 |    Panel_add(this, (Object*) ListItem_new("Idle",
IOPriority_Idle));
           |      |    ~                         ^
           |      |    |                         |
           |      |    |                         (134) returning to
‘IOPriorityPanel_new’ from ‘ListItem_new’
           |      |    (135) calling ‘Panel_add’ from ‘IOPriorityPanel_new’
           |
           +--> ‘Panel_add’: events 136-137
                  |
                  |Panel.c:120:6:
                  |  120 | void Panel_add(Panel* this, Object* o) {
                  |      |      ^
                  |      |      |
                  |      |      (136) entry to ‘Panel_add’
                  |......
                  |  123 |    Vector_add(this->items, o);
                  |      |    ~  
                  |      |    |
                  |      |    (137) calling ‘Vector_add’ from ‘Panel_add’
                  |
                  +--> ‘Vector_add’: events 138-139
                         |
                         |Vector.c:369:6:
                         |  369 | void Vector_add(Vector* this, void* data_) {
                         |      |      ^
                         |      |      |
                         |      |      (138) entry to ‘Vector_add’
                         |......
                         |  374 |    Vector_set(this, this->items, data);
                         |      |    ~  
                         |      |    |
                         |      |    (139) calling ‘Vector_set’ from
‘Vector_add’
                         |
                         +--> ‘Vector_set’: events 140-141
                                |
                                |  333 | void Vector_set(Vector* this, int idx,
void* data_) {
                                |      |      ^
                                |      |      |
                                |      |      (140) entry to ‘Vector_set’
                                |......
                                |  339 |    Vector_resizeIfNecessary(this, idx
+ 1);
                                |      |    ~  
                                |      |    |
                                |      |    (141) calling
‘Vector_resizeIfNecessary’ from ‘Vector_set’
                                |
                                +--> ‘Vector_resizeIfNecessary’: events 142-145
                                       |
                                       |  199 | static void
Vector_resizeIfNecessary(Vector* this, int newSize) {
                                       |      |             ^
                                       |      |             |
                                       |      |             (142) entry to
‘Vector_resizeIfNecessary’
                                       |  200 |    assert(newSize >= 0);
                                       |  201 |    if (newSize >
this->arraySize) {
                                       |      |       ~      
                                       |      |       |
                                       |      |       (143) following ‘true’
branch...
                                       |......
                                       |  204 |       this->arraySize = newSize
+ this->growthRate;
                                       |      |                                
      ~
                                       |      |                                
      |
                                       |      |                                
      (144) ...to here
                                       |  205 |       this->array =
(Object**)xReallocArrayZero(this->array, oldSize, this->arraySize,
sizeof(Object*));
                                       |      |                               ~
                                       |      |                               |
                                       |      |                              
(145) calling ‘xReallocArrayZero’ from ‘Vector_resizeIfNecessary’
                                       |
                                       +--> ‘xReallocArrayZero’: events 146-148
                                              |
                                              |XUtils.c:90:7:
                                              |   90 | void*
xReallocArrayZero(void* ptr, size_t prevmemb, size_t newmemb, size_t size) {
                                              |      |       ^
                                              |      |       |
                                              |      |       (146) entry to
‘xReallocArrayZero’
                                              |......
                                              |   93 |    if (prevmemb ==
newmemb) {
                                              |      |       ~
                                              |      |       |
                                              |      |       (147) following
‘false’ branch (when ‘prevmemb_8(D) != newmemb_9(D)’)...
                                              |......
                                              |   97 |    void* ret =
xReallocArray(ptr, newmemb, size);
                                              |      |                ~
                                              |      |                |
                                              |      |                (148)
inlined call to ‘xReallocArray’ from ‘xReallocArrayZero’
                                              |
                                              +--> ‘xReallocArray’: events
149-152
                                                     |
                                                     |   84 |    if (SIZE_MAX /
nmemb < size) {
                                                     |      |       ~          
      ^
                                                     |      |       |          
      |
                                                     |      |       |          
      (149) ...to here
                                                     |      |       (150)
following ‘false’ branch...
                                                     |......
                                                     |   87 |    return
xRealloc(ptr, nmemb * size);
                                                     |      |           ~       
                                                     |      |           |
                                                     |      |           (151)
...to here
                                                     |      |           (152)
calling ‘xRealloc’ from ‘xReallocArrayZero’
                                                     |
                                                   ‘xRealloc’: events 153-158
                                                     |
                                                     |   64 | void*
xRealloc(void* ptr, size_t size) {
                                                     |      |       ^
                                                     |      |       |
                                                     |      |       (153) entry
to ‘xRealloc’
                                                     |   65 |    assert(size >
0);
                                                     |   66 |    void* data =
size ? realloc(ptr, size) : NULL; // deepcode ignore MemoryLeakOnRealloc: this
goes to fail()
                                                     |      |                  
     ~                  ~
                                                     |      |                  
     |                  |
                                                     |      |                  
     |                  (154) following ‘true’ branch (when ‘size_1(D) !=
0’)...
                                                     |      |                  
     (155) ...to here
                                                     |      |                  
     (156) allocated here
                                                     |      |                  
     (157) when ‘realloc’ succeeds, moving buffer
                                                     |   67 |    if (!data) {
                                                     |      |       ~
                                                     |      |       |
                                                     |      |       (158)
‘realloc (ptr_4(D), size_1(D))’ leaks here; was allocated at (156)
                                                     |
```

The following details can likely be skipped:
- (2), as that branch does not have any influence on the later outcome and is
implied by the later path taken
- events (4)-(8) could be simplified to just note that a non-NULL pointer is
returned from that call
- (9) follows from the non-NULL return in (8); could be either skipped or
otherwise some lifeliness chain printed
- The call starting at (12) through (135) could be greatly shortened, as
several of the calls there repeat.
- The actually important stuff seems to start at events (142) onwards.

Steps to reproduce:
- Clone upstream htop at eb27a94ba411793aa1a25c331b3e1bb328739583
- ./configure CC=gcc-14 CFLAGS="-fanalyzer -Wanalyzer-infinite-loop
-mtune=native -march=native -flto=8 -O3"
- make clean && make
- Observe the output from the LTO/linking stage

If using
./configure CC=gcc-14 CFLAGS="-fanalyzer -Wanalyzer-infinite-loop -mtune=native
-march=native"
instead, there's no message from the linking stage and the two reports from the
compile stage are reasonably explained (one being a potential issue in htop,
the other is https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114586).

Reply via email to