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

Reply via email to