https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109847
Bug ID: 109847 Summary: -Wanalyzer-out-of-bounds false positive with Emacs tagged pointers Product: gcc Version: 13.1.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 55078 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=55078&action=edit compile with 'gcc -O2 -fanalyzer' to illustrate the false positive I ran into this problem when compiling GNU Emacs with GCC 13.1.1 20230426 (Red Hat 13.1.1-1) on x86-64. The attached file contains stripped-down source code to illustrate the problem. Compile it with: gcc -O2 -fanalyzer -S analyzer-bounds-bug.i The output is shown below. This output is incorrect, since it is complaining about the access to the 'size' member, but that access is never executed as the previous condition '! (((unsigned) (long) a - 5) & 7)' is false. If you change line 51 from 'CHECK_STRING (buffer_or_name);' to 'if (0) CHECK_STRING (buffer_or_name);' the warning goes away. But line 51 is executed after the line being warned about. It looks like line 51 is confusing the analyzer into thinking that line 50 can be executed in an impossible way. As can be seen below, GCC also issues an incorrect -Wanalyzer-use-of-uninitialized-value diagnostic, but since that may be cascading from the earlier bug I am not reporting it separately. In function ‘PSEUDOVECTORP’, inlined from ‘BUFFERP’ at analyzer-bounds-bug.i:44:10, inlined from ‘Fget_buffer’ at analyzer-bounds-bug.i:50:9: analyzer-bounds-bug.i:39:50: warning: stack-based buffer under-read [CWE-127] [-Wanalyzer-out-of-bounds] 39 | && ((struct buffer *) ((char *) a - 5))->size == code); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~ ‘init_buffer’: events 1-2 | | 56 | init_buffer (void) | | ^~~~~~~~~~~ | | | | | (1) entry to ‘init_buffer’ |...... | 60 | Fget_buffer (scratch); | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (2) calling ‘Fget_buffer’ from ‘init_buffer’ | +--> ‘Fget_buffer’: events 3-4 | | 48 | Fget_buffer (Lisp_Object buffer_or_name) | | ^~~~~~~~~~~ | | | | | (3) entry to ‘Fget_buffer’ | 49 | { | 50 | if (! BUFFERP (buffer_or_name)) | | ~ | | | | | (4) inlined call to ‘BUFFERP’ from ‘Fget_buffer’ | +--> ‘BUFFERP’: event 5 | | 44 | return PSEUDOVECTORP (a, 13); | | ^ | | | | | (5) inlined call to ‘PSEUDOVECTORP’ from ‘BUFFERP’ | +--> ‘PSEUDOVECTORP’: events 6-8 | | 38 | return (! (((unsigned) (long) a - 5) & 7) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 39 | && ((struct buffer *) ((char *) a - 5))->size == code); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | (7) ...to here | | (6) following ‘true’ branch... (8) out-of-bounds read at byte -1 but ‘<U1d80>’ starts at byte 0 | analyzer-bounds-bug.i:39:50: warning: use of uninitialized value ‘((struct buffer *)((char *)buffer_or_name + 3))[2305843009213693951].size’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value] 39 | && ((struct buffer *) ((char *) a - 5))->size == code); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~ ‘init_buffer’: events 1-3 | | 56 | init_buffer (void) | | ^~~~~~~~~~~ | | | | | (1) entry to ‘init_buffer’ |...... | 59 | (&(struct Lisp_String) {{{9, "*scratch*"}}}, 4); | | ~ | | | | | (2) region created on stack here | 60 | Fget_buffer (scratch); | | ~~~~~~~~~~~~~~~~~~~~~ | | | | | (3) calling ‘Fget_buffer’ from ‘init_buffer’ | +--> ‘Fget_buffer’: events 4-5 | | 48 | Fget_buffer (Lisp_Object buffer_or_name) | | ^~~~~~~~~~~ | | | | | (4) entry to ‘Fget_buffer’ | 49 | { | 50 | if (! BUFFERP (buffer_or_name)) | | ~ | | | | | (5) inlined call to ‘BUFFERP’ from ‘Fget_buffer’ | +--> ‘BUFFERP’: event 6 | | 44 | return PSEUDOVECTORP (a, 13); | | ^ | | | | | (6) inlined call to ‘PSEUDOVECTORP’ from ‘BUFFERP’ | +--> ‘PSEUDOVECTORP’: events 7-9 | | 38 | return (! (((unsigned) (long) a - 5) & 7) | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 39 | && ((struct buffer *) ((char *) a - 5))->size == code); | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | (8) ...to here | | (7) following ‘true’ branch... (9) use of uninitialized value ‘((struct buffer *)((char *)buffer_or_name + 3))[2305843009213693951].size’ here |