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