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

            Bug ID: 127896
           Summary: -Wanalyzer-out-of-bounds false positives in Emacs
                    array of size 5
           Product: gcc
           Version: 16.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 65845
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65845&action=edit
Compile this with "gcc -S -fanalyzer -O2" to see the bug

This is gcc (GCC) 16.2.1 20260819 (Red Hat 16.2.1-2) on x86-64. Compile the
attached file (derived from current Emacs master) with:

gzip -d t.i.gz
gcc -S -fanalyzer -O2 t.i

The output starts as follows but then goes on for much longer in the same vein.
The diagnostics are obviously wrong, as i is obviously in the range 0..4
because props_idx is in the range 0..5 and this can easily be determined by
static analysis of the containing function.

I plan to work around the problem by disabling this warning when compiling the
affected source file.

----

t.i: In function ‘smc_save_yourself_CB’:
t.i:115976:19: warning: stack-based buffer over-read [CWE-126]
[-Wanalyzer-out-of-bounds]
115976 |       xfree (props[i]->type);
       |              ~~~~~^~~
  ‘smc_save_yourself_CB’: events 1-3
    │
    │115827 | smc_save_yourself_CB (SmcConn smcConn,
    │       | ^~~~~~~~~~~~~~~~~~~~
    │       | |
    │       | (1) entry to ‘smc_save_yourself_CB’
    │.......
    │115840 |   SmProp *props[5];
    │       |           ~~~~~
    │       |           |
    │       |           (2) capacity: 40 bytes
    │.......
    │115853 |   if (! STRINGP (globals.f_Vinvocation_name) || ! STRINGP
(user_login_name))
    │       |      ~
    │       |      |
    │       |      (3) following ‘false’ branch... ─>─┐
    │       |                                         │
    │
  ‘smc_save_yourself_CB’: event 4
    │
    │       |                                         │
    │       |┌────────────────────────────────────────┘
    │115853 |│  if (! STRINGP (globals.f_Vinvocation_name) || ! STRINGP
(user_login_name))
    │       |│                                                  ^
    │       |│                                                  |
    │       |└─────────────────────────────────────────────────>(4) inlined
call to ‘STRINGP’ from ‘smc_save_yourself_CB’
    │
    └──> ‘STRINGP’: event 5
           │
           │20049 |   return TAGGEDP (x, Lisp_String);
           │      |          ^
           │      |          |
           │      |          (5) inlined call to ‘TAGGEDP’ from ‘STRINGP’
           │
           └──> ‘TAGGEDP’: event 6
                  │
                  │12775 |   return (XTYPE (a) == (tag));
                  │      |           ^
                  │      |           |
                  │      |           (6) inlined call to ‘XTYPE’ from ‘TAGGEDP’
                  │
                  └──> ‘XTYPE’: event 7
                         │
                         │12758 |   return ((enum Lisp_Type) (XLI (a) &
~(((0x7fffffffffffffffL
                         │      |                             ^
                         │      |                             |
                         │      |                             (7) inlined call
to ‘XLI’ from ‘XTYPE’
                         │
                         └──> ‘XLI’: event 8
                                │
                                │12737 |   return ((EMACS_INT) (o));
                                │      |          ~^~~~~~~~~~~~~~~~
                                │      |           |
                                │      |           (8) ...to here
                                │
    <───────────────────────────┘
    │
  ‘smc_save_yourself_CB’: events 9-16
    │
    │115853 |   if (! STRINGP (globals.f_Vinvocation_name) || ! STRINGP
(user_login_name))
    │       |      
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    │       |                                              |
    │       |                                              (9) following
‘false’ branch... ─>─┐
    │       |                                                                  
              │
    │.......
    │       |                                                                  
              │
    │      
|┌────────────────────────────────────────────────────────────────────────────────┘
    │115857 |│  props[props_idx] = &prop_ptr[props_idx];
    │       |│  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~     
    │       |│                   |
    │       |└──────────────────>(10) ...to here
    │.......
    │115925 |   if (
    │       |      ~                                        
    │       |      |
    │       |      (11) following ‘false’ branch... ─>─┐
    │       |                                          │
    │.......
    │       |                                          │
    │       |┌─────────────────────────────────────────┘
    │115935 |│  props[props_idx]->num_vals = i;
    │       |│  ~~~~~~~~~~~~~~~~                            
    │       |│       |
    │       |└──────>(12) ...to here
    │.......
    │115950 |   if (cwd)
    │       |      ~                                        
    │       |      |
    │       |      (13) following ‘false’ branch (when ‘cwd’ is NULL)... ─>─┐
    │       |                                                               │
    │.......
    │       |                                                               │
    │       |┌──────────────────────────────────────────────────────────────┘
    │115959 |│  for (i = 1; i < initial_argc; ++i)
    │       |│  ~~~                                         
    │       |│  |
    │       |└─>(14) ...to here
    │.......
    │115974 |   for (i = 0; i < props_idx; ++i)
    │       |               ~~~~~~~~~~~~~                   
    │       |                 |
    │       |                 (15) following ‘true’ branch (when ‘i <
props_idx’)... ─>─┐
    │       |                                                                  
        │
    │       |                                                                  
        │
    │      
|┌──────────────────────────────────────────────────────────────────────────┘
    │115975 |│    {
    │115976 |│      xfree (props[i]->type);
    │       |│             ~~~~~~~~                         
    │       |│                  |
    │       |└─────────────────>(16) ...to here
    │
  ‘smc_save_yourself_CB’: events 17-18
    │
    │115974 |   for (i = 0; i < props_idx; ++i)
    │       |               ~~^~~~~~~~~~~
    │       |                 |
    │       |                 (17) following ‘true’ branch (when ‘i <
props_idx’)... ─>─┐
    │       |                                                                  
        │
    │       |                                                                  
        │
    │      
|┌──────────────────────────────────────────────────────────────────────────┘
    │115975 |│    {
    │115976 |│      xfree (props[i]->type);
    │       |│             ~~~~~~~~
    │       |│                  |
    │       |└─────────────────>(18) ...to here
    │
  ‘smc_save_yourself_CB’: events 19-20
    │
    │115974 |   for (i = 0; i < props_idx; ++i)
    │       |               ~~^~~~~~~~~~~
    │       |                 |
    │       |                 (19) following ‘true’ branch (when ‘i <
props_idx’)... ─>─┐
    │       |                                                                  
        │
    │       |                                                                  
        │
    │      
|┌──────────────────────────────────────────────────────────────────────────┘
    │115975 |│    {
    │115976 |│      xfree (props[i]->type);
    │       |│             ~~~~~~~~
    │       |│                  |
    │       |└─────────────────>(20) ...to here
    │
  ‘smc_save_yourself_CB’: events 21-22
    │
    │115974 |   for (i = 0; i < props_idx; ++i)
    │       |               ~~^~~~~~~~~~~
    │       |                 |
    │       |                 (21) following ‘true’ branch (when ‘i <
props_idx’)... ─>─┐
    │       |                                                                  
        │
    │       |                                                                  
        │
    │      
|┌──────────────────────────────────────────────────────────────────────────┘
    │115975 |│    {
    │115976 |│      xfree (props[i]->type);
    │       |│             ~~~~~~~~
    │       |│                  |
    │       |└─────────────────>(22) ...to here
    │
  ‘smc_save_yourself_CB’: events 23-24
    │
    │115974 |   for (i = 0; i < props_idx; ++i)
    │       |               ~~^~~~~~~~~~~
    │       |                 |
    │       |                 (23) following ‘true’ branch (when ‘i <
props_idx’)... ─>─┐
    │       |                                                                  
        │
    │       |                                                                  
        │
    │      
|┌──────────────────────────────────────────────────────────────────────────┘
    │115975 |│    {
    │115976 |│      xfree (props[i]->type);
    │       |│             ~~~~~~~~
    │       |│                  |
    │       |└─────────────────>(24) ...to here
    │
  ‘smc_save_yourself_CB’: events 25-27
    │
    │115974 |   for (i = 0; i < props_idx; ++i)
    │       |               ~~^~~~~~~~~~~
    │       |                 |
    │       |                 (25) following ‘true’ branch (when ‘i <
props_idx’)... ─>─┐
    │       |                                                                  
        │
    │       |                                                                  
        │
    │      
|┌──────────────────────────────────────────────────────────────────────────┘
    │115975 |│    {
    │115976 |│      xfree (props[i]->type);
    │       |│             ~~~~~~~~
    │       |│                  |
    │       |└─────────────────>(26) ...to here
    │       |                   (27) ⚠️  out-of-bounds read from byte 40 till
byte 47 but ‘props’ ends at byte 40
    │
t.i:115976:19: note: read of 8 bytes from after the end of ‘props’
115976 |       xfree (props[i]->type);
       |              ~~~~~^~~
t.i:115976:19: note: valid subscripts for ‘props’ are ‘[0]’ to ‘[4]’

                                        ┌───────────────────────────────────┐
                                        │read of ‘struct SmProp *’ (8 bytes)│
                                        └───────────────────────────────────┘
                                                          ^
                                                          │
                                                          │
  ┌───────────┬───────────┬────────────┐┌───────────────────────────────────┐
  │    [0]    │    ...    │    [4]     ││                                   │
  ├───────────┴───────────┴────────────┤│         after valid range         │
  │‘props’ (type: ‘struct SmProp *[5]’)││                                   │
  └────────────────────────────────────┘└───────────────────────────────────┘
  ├─────────────────┬──────────────────┤├─────────────────┬─────────────────┤
                    │                                     │
            ╭───────┴──────╮                  ╭───────────┴───────────╮
            │size: 40 bytes│                  │⚠️  over-read of 8 bytes│
            ╰──────────────╯                  ╰───────────────────────╯

Reply via email to