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).