https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114893
Bug ID: 114893 Summary: -Wanalyzer-null-dereference false positive in Emacs select_window Product: gcc Version: 14.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: eggert at cs dot ucla.edu Target Milestone: --- Created attachment 58074 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=58074&action=edit "gunzip t.i; gcc -std=gnu23 -O2 -S -fanalyzer t.i" to see false positivfe This is gcc (GCC) 14.0.1 20240411 (Red Hat 14.0.1-0) on x86-64. Uncompress the attached program t.i (derived from Emacs src/textconv.c) and compile with: gcc -std=gnu23 -O2 -S -fanalyzer t.i The incorrect output is at the end of this bug report. The bug seems to be fragile, in that if I edit the program a bit the false positive goes away. A curious thing is that GCC complains about dereferencing w in line 94026 in this context: 94023 struct window *w; 94024 w = XWINDOW (window); 94025 if ((w)->mini 94026 && BUFFERP ((w)->contents) 94027 && !EQ (window, Factive_minibuffer_window ())) 94028 ... even though line 95026 is reachable only via line 94025, which dereferences w but is not diagnosed. Anyway, here's the incorrect output: t.i: In function ‘select_window’: t.i:94026:10: warning: dereference of NULL ‘w’ [CWE-476] [-Wanalyzer-null-dereference] 94026 | && BUFFERP ((w)->contents) | ^~~~~~~~~~~~~~~~~~~~~~~ ‘handle_pending_conversion_events’: events 1-3 | |95150 | handle_pending_conversion_events (void) | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (1) entry to ‘handle_pending_conversion_events’ |...... |95166 | for ((tail) = Vframe_list; (CONSP (tail) && (frame = XCAR (tail), true)); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | (3) inlined call to ‘XCAR’ from ‘handle_pending_conversion_events’ | | (2) following ‘true’ branch... | +--> ‘XCAR’: event 4 | | 8266 | return XCONS (c)->u.s.car; | | ^ | | | | | (4) inlined call to ‘XCONS’ from ‘XCAR’ | +--> ‘XCONS’: event 5 | | 8244 | return ((struct Lisp_Cons *) ((uintptr_t) XLP (a) - | | ^~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | <-------------+ | ‘handle_pending_conversion_events’: events 6-10 | |95181 | if (w && (last_point != w->ephemeral_last_point)) | | ^ | | | | | (6) following ‘false’ branch (when ‘w’ is NULL)... |...... |95199 | action = f->conversion.actions; | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (7) ...to here |95200 | if (!action) | | ~ | | | | | (8) following ‘false’ branch (when ‘action’ is non-NULL)... |95201 | break; |95202 | if (action->operation == TEXTCONV_BARRIER | | ~~~~~~~~~~~~~~~~~ | | | | | (9) ...to here |...... |95207 | w = handle_pending_conversion_events_1 (f, action); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (10) calling ‘handle_pending_conversion_events_1’ from ‘handle_pending_conversion_events’ | +--> ‘handle_pending_conversion_events_1’: events 11-16 | |95048 | handle_pending_conversion_events_1 (struct frame *f, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (11) entry to ‘handle_pending_conversion_events_1’ |...... |95062 | if (conversion_disabled_p ()) | | ~ | | | | | (12) following ‘false’ branch... |95063 | return ((void *) 0); |95064 | context.check = false; | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (13) ...to here |...... |95078 | switch (operation) | | ~~~~~~ | | | | | (14) following ‘case 1:’ branch... |...... |95083 | case TEXTCONV_END_BATCH_EDIT: | | ~~~~ | | | | | (15) ...to here |...... |95087 | (WINDOWP (f->old_selected_window) | | ~ | | | | | (16) inlined call to ‘WINDOWP’ from ‘handle_pending_conversion_events_1’ | +--> ‘WINDOWP’: event 17 | |17514 | return PSEUDOVECTORP (a, PVEC_WINDOW); | | ^ | | | | | (17) inlined call to ‘PSEUDOVECTORP’ from ‘WINDOWP’ | +--> ‘PSEUDOVECTORP’: events 18-20 | | 7917 | return (TAGGEDP (a, Lisp_Vectorlike) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7918 | && | | ^~ | | | | | (18) following ‘true’ branch... | | (20) following ‘true’ branch... | 7919 | ((((union vectorlike_header *) ((uintptr_t) XLP (a) - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (19) ...to here | 7920 | (uintptr_t) ((Lisp_Word_tag) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7921 | (Lisp_Vectorlike) << | | ~~~~~~~~~~~~~~~~~~~~ | 7922 | (((0x7fffffffffffffffL | | ~~~~~~~~~~~~~~~~~~~~~~ | 7923 | >> (3 - 1)) / 2 < | | ~~~~~~~~~~~~~~~~~ | 7924 | (9223372036854775807L)) | | ~~~~~~~~~~~~~~~~~~~~~~~ | 7925 | ? 0 : VALBITS))))-> | | ~~~~~~~~~~~~~~~~~~~ | 7926 | size & (((9223372036854775807L) - (9223372036854775807L) / 2) | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7927 | PVEC_TYPE_MASK)) == | | ~~~~~~~~~~~~~~~~~~~ | 7928 | (((9223372036854775807L) - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7929 | (9223372036854775807L) / | | ~~~~~~~~~~~~~~~~~~~~~~~~ | 7930 | 2) | (code << PSEUDOVECTOR_AREA_BITS)))); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | <-------------+ | ‘handle_pending_conversion_events_1’: events 21-22 | |95088 | && BUFFERP ((XWINDOW (f->old_selected_window))->contents))) | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (21) ...to here | | (22) inlined call to ‘BUFFERP’ from ‘handle_pending_conversion_events_1’ | +--> ‘BUFFERP’: event 23 | |18601 | return PSEUDOVECTORP (a, PVEC_BUFFER); | | ^ | | | | | (23) inlined call to ‘PSEUDOVECTORP’ from ‘BUFFERP’ | +--> ‘PSEUDOVECTORP’: events 24-26 | | 7917 | return (TAGGEDP (a, Lisp_Vectorlike) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7918 | && | | ^~ | | | | | (24) following ‘true’ branch... | | (26) following ‘true’ branch... | 7919 | ((((union vectorlike_header *) ((uintptr_t) XLP (a) - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (25) ...to here | 7920 | (uintptr_t) ((Lisp_Word_tag) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7921 | (Lisp_Vectorlike) << | | ~~~~~~~~~~~~~~~~~~~~ | 7922 | (((0x7fffffffffffffffL | | ~~~~~~~~~~~~~~~~~~~~~~ | 7923 | >> (3 - 1)) / 2 < | | ~~~~~~~~~~~~~~~~~ | 7924 | (9223372036854775807L)) | | ~~~~~~~~~~~~~~~~~~~~~~~ | 7925 | ? 0 : VALBITS))))-> | | ~~~~~~~~~~~~~~~~~~~ | 7926 | size & (((9223372036854775807L) - (9223372036854775807L) / 2) | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7927 | PVEC_TYPE_MASK)) == | | ~~~~~~~~~~~~~~~~~~~ | 7928 | (((9223372036854775807L) - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7929 | (9223372036854775807L) / | | ~~~~~~~~~~~~~~~~~~~~~~~~ | 7930 | 2) | (code << PSEUDOVECTOR_AREA_BITS)))); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | <-------------+ | ‘handle_pending_conversion_events_1’: events 27-30 | |95090 | if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE) | | ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~ | | | | | | | (27) ...to here | | (28) following ‘true’ branch... |95091 | { |95092 | locate_and_save_position_in_field (f, w, false); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (29) ...to here | | (30) calling ‘locate_and_save_position_in_field’ from ‘handle_pending_conversion_events_1’ | +--> ‘locate_and_save_position_in_field’: events 31-32 | |94743 | locate_and_save_position_in_field (struct frame *f, struct window *w, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (31) entry to ‘locate_and_save_position_in_field’ |...... |94758 | select_window (window, builtin_lisp_symbol (1)); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (32) calling ‘select_window’ from ‘locate_and_save_position_in_field’ | +--> ‘select_window’: events 33-34 | |94021 | select_window (Lisp_Object window, Lisp_Object norecord) | | ^~~~~~~~~~~~~ | | | | | (33) entry to ‘select_window’ |...... |94024 | w = XWINDOW (window); | | ~ | | | | | (34) inlined call to ‘XWINDOW’ from ‘select_window’ | +--> ‘XWINDOW’: event 35 | |17526 | return ((struct window *) ((uintptr_t) XLP (a) - | | ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (35) ‘w’ is NULL |17527 | (uintptr_t) ((Lisp_Word_tag) (Lisp_Vectorlike) << | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |17528 | (((0x7fffffffffffffffL >> (3 - 1)) / | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |17529 | 2 < | | ~~~ |17530 | (9223372036854775807L)) ? 0 : | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |17531 | VALBITS)))); | | ~~~~~~~~~~~ | <------+ | ‘select_window’: events 36-38 | |94025 | if ((w)->mini | | ^ | | | | | (36) following ‘true’ branch... |94026 | && BUFFERP ((w)->contents) | | ~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (37) ...to here | | (38) dereference of NULL ‘(struct window *)((long unsigned int)window + 18446744073709551611)’ | t.i: In function ‘locate_and_save_position_in_field’: t.i:94760:28: warning: dereference of NULL ‘w’ [CWE-476] [-Wanalyzer-null-dereference] 94760 | make_fixed_natnum (((((w->ephemeral_last_point) > | ~~^~~~~~~~~~~~~~~~~~~~~~~ ‘handle_pending_conversion_events’: events 1-3 | |95150 | handle_pending_conversion_events (void) | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (1) entry to ‘handle_pending_conversion_events’ |...... |95166 | for ((tail) = Vframe_list; (CONSP (tail) && (frame = XCAR (tail), true)); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | (3) inlined call to ‘XCAR’ from ‘handle_pending_conversion_events’ | | (2) following ‘true’ branch... | +--> ‘XCAR’: event 4 | | 8266 | return XCONS (c)->u.s.car; | | ^ | | | | | (4) inlined call to ‘XCONS’ from ‘XCAR’ | +--> ‘XCONS’: event 5 | | 8244 | return ((struct Lisp_Cons *) ((uintptr_t) XLP (a) - | | ^~~~~~~~~~~~~~~~~~~ | | | | | (5) ...to here | <-------------+ | ‘handle_pending_conversion_events’: events 6-10 | |95181 | if (w && (last_point != w->ephemeral_last_point)) | | ^ | | | | | (6) following ‘false’ branch (when ‘w’ is NULL)... |...... |95199 | action = f->conversion.actions; | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (7) ...to here |95200 | if (!action) | | ~ | | | | | (8) following ‘false’ branch (when ‘action’ is non-NULL)... |95201 | break; |95202 | if (action->operation == TEXTCONV_BARRIER | | ~~~~~~~~~~~~~~~~~ | | | | | (9) ...to here |...... |95207 | w = handle_pending_conversion_events_1 (f, action); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (10) calling ‘handle_pending_conversion_events_1’ from ‘handle_pending_conversion_events’ | +--> ‘handle_pending_conversion_events_1’: events 11-16 | |95048 | handle_pending_conversion_events_1 (struct frame *f, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (11) entry to ‘handle_pending_conversion_events_1’ |...... |95062 | if (conversion_disabled_p ()) | | ~ | | | | | (12) following ‘false’ branch... |95063 | return ((void *) 0); |95064 | context.check = false; | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (13) ...to here |...... |95078 | switch (operation) | | ~~~~~~ | | | | | (14) following ‘case 1:’ branch... |...... |95083 | case TEXTCONV_END_BATCH_EDIT: | | ~~~~ | | | | | (15) ...to here |...... |95087 | (WINDOWP (f->old_selected_window) | | ~ | | | | | (16) inlined call to ‘WINDOWP’ from ‘handle_pending_conversion_events_1’ | +--> ‘WINDOWP’: event 17 | |17514 | return PSEUDOVECTORP (a, PVEC_WINDOW); | | ^ | | | | | (17) inlined call to ‘PSEUDOVECTORP’ from ‘WINDOWP’ | +--> ‘PSEUDOVECTORP’: events 18-20 | | 7917 | return (TAGGEDP (a, Lisp_Vectorlike) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7918 | && | | ^~ | | | | | (18) following ‘true’ branch... | | (20) following ‘true’ branch... | 7919 | ((((union vectorlike_header *) ((uintptr_t) XLP (a) - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (19) ...to here | 7920 | (uintptr_t) ((Lisp_Word_tag) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7921 | (Lisp_Vectorlike) << | | ~~~~~~~~~~~~~~~~~~~~ | 7922 | (((0x7fffffffffffffffL | | ~~~~~~~~~~~~~~~~~~~~~~ | 7923 | >> (3 - 1)) / 2 < | | ~~~~~~~~~~~~~~~~~ | 7924 | (9223372036854775807L)) | | ~~~~~~~~~~~~~~~~~~~~~~~ | 7925 | ? 0 : VALBITS))))-> | | ~~~~~~~~~~~~~~~~~~~ | 7926 | size & (((9223372036854775807L) - (9223372036854775807L) / 2) | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7927 | PVEC_TYPE_MASK)) == | | ~~~~~~~~~~~~~~~~~~~ | 7928 | (((9223372036854775807L) - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7929 | (9223372036854775807L) / | | ~~~~~~~~~~~~~~~~~~~~~~~~ | 7930 | 2) | (code << PSEUDOVECTOR_AREA_BITS)))); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | <-------------+ | ‘handle_pending_conversion_events_1’: events 21-22 | |95088 | && BUFFERP ((XWINDOW (f->old_selected_window))->contents))) | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (21) ...to here | | (22) inlined call to ‘BUFFERP’ from ‘handle_pending_conversion_events_1’ | +--> ‘BUFFERP’: event 23 | |18601 | return PSEUDOVECTORP (a, PVEC_BUFFER); | | ^ | | | | | (23) inlined call to ‘PSEUDOVECTORP’ from ‘BUFFERP’ | +--> ‘PSEUDOVECTORP’: events 24-26 | | 7917 | return (TAGGEDP (a, Lisp_Vectorlike) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7918 | && | | ^~ | | | | | (24) following ‘true’ branch... | | (26) following ‘true’ branch... | 7919 | ((((union vectorlike_header *) ((uintptr_t) XLP (a) - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (25) ...to here | 7920 | (uintptr_t) ((Lisp_Word_tag) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7921 | (Lisp_Vectorlike) << | | ~~~~~~~~~~~~~~~~~~~~ | 7922 | (((0x7fffffffffffffffL | | ~~~~~~~~~~~~~~~~~~~~~~ | 7923 | >> (3 - 1)) / 2 < | | ~~~~~~~~~~~~~~~~~ | 7924 | (9223372036854775807L)) | | ~~~~~~~~~~~~~~~~~~~~~~~ | 7925 | ? 0 : VALBITS))))-> | | ~~~~~~~~~~~~~~~~~~~ | 7926 | size & (((9223372036854775807L) - (9223372036854775807L) / 2) | | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7927 | PVEC_TYPE_MASK)) == | | ~~~~~~~~~~~~~~~~~~~ | 7928 | (((9223372036854775807L) - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7929 | (9223372036854775807L) / | | ~~~~~~~~~~~~~~~~~~~~~~~~ | 7930 | 2) | (code << PSEUDOVECTOR_AREA_BITS)))); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | <-------------+ | ‘handle_pending_conversion_events_1’: events 27-30 | |95090 | if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE) | | ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~ | | | | | | | (27) ...to here | | (28) following ‘true’ branch... |95091 | { |95092 | locate_and_save_position_in_field (f, w, false); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (29) ...to here | | (30) calling ‘locate_and_save_position_in_field’ from ‘handle_pending_conversion_events_1’ | +--> ‘locate_and_save_position_in_field’: events 31-32 | |94743 | locate_and_save_position_in_field (struct frame *f, struct window *w, | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (31) entry to ‘locate_and_save_position_in_field’ |...... |94758 | select_window (window, builtin_lisp_symbol (1)); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (32) calling ‘select_window’ from ‘locate_and_save_position_in_field’ | +--> ‘select_window’: events 33-34 | |94021 | select_window (Lisp_Object window, Lisp_Object norecord) | | ^~~~~~~~~~~~~ | | | | | (33) entry to ‘select_window’ |...... |94024 | w = XWINDOW (window); | | ~ | | | | | (34) inlined call to ‘XWINDOW’ from ‘select_window’ | +--> ‘XWINDOW’: event 35 | |17526 | return ((struct window *) ((uintptr_t) XLP (a) - | | ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (35) ‘w’ is NULL |17527 | (uintptr_t) ((Lisp_Word_tag) (Lisp_Vectorlike) << | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |17528 | (((0x7fffffffffffffffL >> (3 - 1)) / | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |17529 | 2 < | | ~~~ |17530 | (9223372036854775807L)) ? 0 : | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |17531 | VALBITS)))); | | ~~~~~~~~~~~ | <------+ | ‘select_window’: event 36 | |94025 | if ((w)->mini | | ^ | | | | | (36) following ‘false’ branch... | ‘select_window’: event 37 | |cc1: | (37): ...to here | <------+ | ‘locate_and_save_position_in_field’: events 38-39 | |94758 | select_window (window, builtin_lisp_symbol (1)); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (38) returning to ‘locate_and_save_position_in_field’ from ‘select_window’ |94759 | ((pos) = |94760 | make_fixed_natnum (((((w->ephemeral_last_point) > | | ~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (39) dereference of NULL ‘w’ |