https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94858
Bug ID: 94858 Summary: False report of memory leak Product: gcc Version: 10.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: addw at phcomp dot co.uk Target Milestone: --- Report of a memory leak - that does not happen. If malloc()/realloc() fails then td->hs_index is left untouched. #include <stdlib.h> #define FALSE 0 #define TRUE 1 #define HASH_EMPTY -1 typedef short hashNx; typedef struct hashSt { hashNx* hs_index; // Indicies into table - hashed to find index int hs_used; // Entries used in hs_index int hs_slots; // Available slots in hs_index } hashSt; void hashEmpty(hashSt* td); int hashAlloc(hashSt* td, int slots) { hashNx* index; // Is the index already at least that big ? if(slots > td->hs_slots) { // New or reallocate ? if(td->hs_index != NULL) index = realloc(td->hs_index, (size_t)slots * sizeof(hashNx)); else index = malloc((size_t)slots * sizeof(hashNx)); if(index == NULL) return(FALSE); // If we get here malloc()/realloc() worked td->hs_index = index; td->hs_slots = slots; } hashEmpty(td); // Clear the index return(TRUE); } /* Mark everything in the hash index as empty. * This is useful if you have deleted something and need to reindex. * It is OK to call this on a table that has not been initialised. */ void hashEmpty(hashSt* td) { hashNx* index; int slots; for(slots = td->hs_slots, index = td->hs_index; --slots >= 0; ) *index++ = HASH_EMPTY; td->hs_used = 0; } cc -O2 -Wall -Wno-pointer-sign -Wconversion -fanalyzer -c -o hasha.o hasha.c In function ‘hashAlloc’: hasha.c:54:14: warning: leak of ‘index’ [CWE-401] [-Wanalyzer-malloc-leak] 54 | td->hs_used = 0; | ~~~~~~~~~~~~^~~ ‘hashAlloc’: events 1-9 | | 22 | if(slots > td->hs_slots) { | | ^ | | | | | (1) following ‘true’ branch... |...... | 25 | if(td->hs_index != NULL) | | ~~~~~~~~~~~~~ | | | | | | | (2) ...to here | | (3) following ‘false’ branch... |...... | 28 | index = malloc((size_t)slots * sizeof(hashNx)); | | ~~~~~~~~~~~~~ | | | | | (4) ...to here | | (5) allocated here | 29 | | 30 | if(index == NULL) | | ~ | | | | | (6) assuming ‘index’ is non-NULL | | (7) following ‘false’ branch (when ‘index’ is non-NULL)... |...... | 33 | td->hs_index = index; | | ~~~~~~~~~~~~~~~~~~~~ | | | | | (8) ...to here |...... | 54 | td->hs_used = 0; | | ~~~~~~~~~~~~~~~ | | | | | (9) ‘index’ leaks here; was allocated at (5) |