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
                         |

Reply via email to