https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118015
Bug ID: 118015 Summary: bogus "check for NULL after already dereferencing it" warning Product: gcc Version: 14.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: bruno at clisp dot org Target Milestone: --- Created attachment 59846 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=59846&action=edit test case i.c Compiling the attached file i.c with gcc 14.2.0 (with -O2 optimization) produces a "warning: check of ‘h’ for NULL after already dereferencing it". But ‘h’ can indeed be NULL here, if the 'break' statement in line 63 was on the execution path. $ gcc -Wall -fanalyzer -S -O2 i.c i.c: In function ‘message_list_delete_header_field’: i.c:66:12: warning: check of ‘h’ for NULL after already dereferencing it [-Wanalyzer-deref-before-check] 66 | if (h != ((void *)0) && *h != '\0') | ^ ‘message_list_delete_header_field’: events 1-27 | | 50 | for (j = 0; j < mlp->nitems; j++) | | ~~^~~~~~~~~~~~~ ~~~ | | | | | | | (17) ...to here | | (1) following ‘true’ branch... | | (18) following ‘true’ branch... | 51 | if (((mlp->item[j])->msgctxt == ((void *)0) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | (2) ...to here | | | (19) ...to here | | (3) following ‘true’ branch... | | (20) following ‘true’ branch... | 52 | && (mlp->item[j])->msgid[0] == '\0') && !mlp->item[j]->obsolete) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | | | | | (6) ...to here | | | | | (23) ...to here | | | | (7) following ‘false’ branch... | | | | (24) following ‘false’ branch... | | | (4) ...to here | | | (21) ...to here | | (5) following ‘true’ branch... | | (22) following ‘true’ branch... |...... | 55 | const char *header = mp->msgstr; | | ~~~~~~ | | | | | (8) ...to here | | (25) ...to here | 56 | const char *h; | 57 | for (h = header; *h != '\0'; ) | | ~~~~~~~~~~ | | | | | | | (9) following ‘true’ branch... | | (26) pointer ‘h’ is dereferenced here | 58 | { | 59 | if (strncmp (h, field, field_len) == 0) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | || | | |(10) ...to here | | (11) following ‘false’ branch... | 60 | break; | 61 | h = strchr (h, '\n'); | | ~~~~~~~~~~~~~~~~ | | | | | (12) ...to here | | (13) when ‘strchr’ returns NULL | 62 | if (h == ((void *)0)) | | ~ | | | | | (14) following ‘true’ branch (when ‘h’ is NULL)... |...... | 66 | if (h != ((void *)0) && *h != '\0') | | ~ | | | | | (15) ...to here | | (16) following ‘false’ branch (when ‘h’ is NULL)... | | (27) pointer ‘h’ is checked for NULL here but it was already dereferenced at (26) |