https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120045
Bug ID: 120045 Summary: analyzer: False positive with guarded NULL dereference Product: gcc Version: 16.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: ibuclaw at gcc dot gnu.org Target Milestone: --- This triggers a warning: ``` char *newarrayU(unsigned size, unsigned length) { if (length == 0 || size == 0) return 0; char *ptr = (char*)__builtin_malloc(size * length); if (!ptr) __builtin_unreachable(); return ptr; } char *newarrayiT(unsigned size, unsigned length) { char* result = newarrayU(size, length); unsigned count = (size * length); while (1) { if (count == 0) break; *result = '0'; result++; count-- ; } return result; } ``` ``` warning: dereference of NULL ‘result’ [CWE-476] [-Wanalyzer-null-dereference] 19 | *result = '0'; | ~~~~~~~~^~~~~ ‘char* newarrayiT(unsigned int, unsigned int)’: events 1-2 │ │ 11 | char *newarrayiT(unsigned size, unsigned length) │ | ^~~~~~~~~~ │ | | │ | (1) entry to ‘newarrayiT’ │ 12 | { │ 13 | char* result = newarrayU(size, length); │ | ~~~~~~~~~~~~~~~~~~~~~~~ │ | | │ | (2) calling ‘newarrayU’ from ‘newarrayiT’ │ └──> ‘char* newarrayU(unsigned int, unsigned int)’: events 3-4 │ │ 1 | char *newarrayU(unsigned size, unsigned length) │ | ^~~~~~~~~ │ | | │ | (3) entry to ‘newarrayU’ │...... │ 4 | return 0; │ | ~ │ | | │ | (4) ‘0’ is NULL │ <──────┘ │ ‘char* newarrayiT(unsigned int, unsigned int)’: events 5-8 │ │ 13 | char* result = newarrayU(size, length); │ | ~~~~~~~~~^~~~~~~~~~~~~~ │ | | │ | (5) return of NULL to ‘newarrayiT’ from ‘newarrayU’ │...... │ 18 | if (count == 0) break; │ | ~~ │ | | │ | (6) following ‘false’ branch (when ‘count != 0’)... ─>─┐ │ | │ │ | │ │ |┌───────────────────────────────────────────────────────────────┘ │ 19 |│ *result = '0'; │ |│ ~~~~~~~~~~~~~ │ |│ | │ |└───────────────>(7) ...to here │ | (8) ⚠️ dereference of NULL ‘result’ │ ``` I can't see the dereference ever being possible however between these three conditions. if (length == 0 || size == 0) return NULL; unsigned count = (size * length); if (count == 0) break; When NULL is returned, then count is also guaranteed to be zero.