https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102671

            Bug ID: 102671
           Summary: -Wanalyzer-null-dereference false positive when
                    compiling GNU Emacs
           Product: gcc
           Version: 11.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: eggert at cs dot ucla.edu
  Target Milestone: ---

Created attachment 51577
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=51577&action=edit
Compile with -fanalyzer -O2 -S on x86-64 to illustrate the bug

I ran into this problem when compiling GNU Emacs with gcc (GCC) 11.2.1 20210728
(Red Hat 11.2.1-1) on x86-64. Compile with:

gcc -fanalyzer -O2 -S analyzer-null-defererence-bug.i

and the output will be the diagnostic at the end of this bug report, which is a
false alarm. Removing the unrelated function wset_buffer suppresses the false
alarm, which suggests that the analysis of wset_buffer is somehow messing up
the analysis of delete_all_child_windows.

I do not observe this problem when compiling with gcc (Ubuntu 10.3.0-1ubuntu1)
10.3.0.


analyzer-null-defererence-bug.i: In function 'PSEUDOVECTORP.part.0':
analyzer-null-defererence-bug.i:23:13: warning: dereference of NULL 'a'
[CWE-476] [-Wanalyzer-null-dereference]
   23 |   return ((a->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))
      |            ~^~~~~~
  'delete_all_child_windows': events 1-4
    |
    |  155 | delete_all_child_windows (struct lisp *window)
    |      | ^~~~~~~~~~~~~~~~~~~~~~~~
    |      | |
    |      | (1) entry to 'delete_all_child_windows'
    |......
    |  158 |   if (!NILP (w->next))
    |      |      ~
    |      |      |
    |      |      (2) following 'true' branch...
    |  159 |     delete_all_child_windows (w->next);
    |      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |     |
    |      |     (3) ...to here
    |      |     (4) calling 'delete_all_child_windows' from
'delete_all_child_windows'
    |
    +--> 'delete_all_child_windows': events 5-8
           |
           |  155 | delete_all_child_windows (struct lisp *window)
           |      | ^~~~~~~~~~~~~~~~~~~~~~~~
           |      | |
           |      | (5) entry to 'delete_all_child_windows'
           |......
           |  158 |   if (!NILP (w->next))
           |      |      ~
           |      |      |
           |      |      (6) following 'true' branch...
           |  159 |     delete_all_child_windows (w->next);
           |      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |     |
           |      |     (7) ...to here
           |      |     (8) calling 'delete_all_child_windows' from
'delete_all_child_windows'
           |
           +--> 'delete_all_child_windows': events 9-14
                  |
                  |  155 | delete_all_child_windows (struct lisp *window)
                  |      | ^~~~~~~~~~~~~~~~~~~~~~~~
                  |      | |
                  |      | (9) entry to 'delete_all_child_windows'
                  |......
                  |  158 |   if (!NILP (w->next))
                  |      |      ~
                  |      |      |
                  |      |      (10) following 'false' branch...
                  |  159 |     delete_all_child_windows (w->next);
                  |  160 |   if (WINDOWP (w->contents))
                  |      |      ~~~~~~~~~~~~~~~~~~~~~~
                  |      |      ||
                  |      |      |(11) ...to here
                  |      |      (12) following 'true' branch...
                  |  161 |     {
                  |  162 |       delete_all_child_windows (w->contents);
                  |      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |       |
                  |      |       (13) ...to here
                  |      |       (14) calling 'delete_all_child_windows' from
'delete_all_child_windows'
                  |
                  +--> 'delete_all_child_windows': events 15-19
                         |
                         |  155 | delete_all_child_windows (struct lisp
*window)
                         |      | ^~~~~~~~~~~~~~~~~~~~~~~~
                         |      | |
                         |      | (15) entry to 'delete_all_child_windows'
                         |......
                         |  158 |   if (!NILP (w->next))
                         |      |      ~
                         |      |      |
                         |      |      (16) following 'false' branch...
                         |  159 |     delete_all_child_windows (w->next);
                         |  160 |   if (WINDOWP (w->contents))
                         |      |      ~~~~~~~~~~~~~~~~~~~~~~
                         |      |      ||
                         |      |      |(17) ...to here
                         |      |      (18) following 'false' branch...
                         |......
                         |  165 | }
                         |      | ~
                         |      | |
                         |      | (19) ...to here
                         |
                  <------+
                  |
                'delete_all_child_windows': events 20-22
                  |
                  |  108 |   w->contents = val;
                  |      |   ~~~~~~~~~~~~~~~~~
                  |      |               |
                  |      |               (21) '(((char *)&*window +
11))[768614336404564650].contents' is NULL
                  |      |               (22) '(((char *)&*window +
11))[768614336404564650].contents' is NULL
                  |......
                  |  162 |       delete_all_child_windows (w->contents);
                  |      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |       |
                  |      |       (20) returning to 'delete_all_child_windows'
from 'delete_all_child_windows'
                  |
           <------+
           |
         'delete_all_child_windows': events 23-26
           |
           |  159 |     delete_all_child_windows (w->next);
           |      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |     |
           |      |     (23) return of NULL to 'delete_all_child_windows' from
'delete_all_child_windows'
           |  160 |   if (WINDOWP (w->contents))
           |      |      ~
           |      |      |
           |      |      (24) following 'true' branch...
           |  161 |     {
           |  162 |       delete_all_child_windows (w->contents);
           |      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |       |
           |      |       (25) ...to here
           |      |       (26) calling 'delete_all_child_windows' from
'delete_all_child_windows'
           |
           +--> 'delete_all_child_windows': events 27-30
                  |
                  |   90 |   return PSEUDOVECTORP (a, 12);
                  |      |          ~~~~~~~~~~~~~~~~~~~~~
                  |      |          |
                  |      |          (30) calling 'PSEUDOVECTORP' from
'delete_all_child_windows'
                  |......
                  |  155 | delete_all_child_windows (struct lisp *window)
                  |      | ^~~~~~~~~~~~~~~~~~~~~~~~
                  |      | |
                  |      | (27) entry to 'delete_all_child_windows'
                  |......
                  |  158 |   if (!NILP (w->next))
                  |      |      ~
                  |      |      |
                  |      |      (28) following 'false' branch...
                  |  159 |     delete_all_child_windows (w->next);
                  |  160 |   if (WINDOWP (w->contents))
                  |      |       ~~~~~~~~~~~~~~~~~~~~~
                  |      |       |
                  |      |       (29) ...to here
                  |
                  +--> 'PSEUDOVECTORP': events 31-32
                         |
                         |   28 | PSEUDOVECTORP (struct lisp *a, int code)
                         |      | ^~~~~~~~~~~~~
                         |      | |
                         |      | (31) entry to 'PSEUDOVECTORP'
                         |   29 | {
                         |   30 |   if (! VECTORLIKEP (a))
                         |      |      ~
                         |      |      |
                         |      |      (32) following 'false' branch...
                         |
                       'PSEUDOVECTORP': event 33
                         |
                         |cc1:
                         | (33): ...to here
                         |
                       'PSEUDOVECTORP': event 34
                         |
                         |cc1:
                         | (34): calling 'PSEUDOVECTORP.part.0' from
'PSEUDOVECTORP'
                         |
                         +--> 'PSEUDOVECTORP.part.0': events 35-36
                                |
                                |   23 |   return ((a->size &
(PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))
                                |      |            ~~~~~~~
                                |      |             |
                                |      |             (36) dereference of NULL
'a'
                                |......
                                |   28 | PSEUDOVECTORP (struct lisp *a, int
code)
                                |      | ^~~~~~~~~~~~~
                                |      | |
                                |      | (35) entry to 'PSEUDOVECTORP.part.0'
                                |

Reply via email to