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

            Bug ID: 96509
           Summary: out of bounds access makes a bounded loop infinite
                    with inlining
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

The one-byte buffer overflow turns the bounded loop in the test case below into
an infinite one.  GCC does issue a warning which is enabled by default, but the
transformation is still obviously problematic due to its security implications.

$ cat x.c && gcc -O2 -S -fdump-tree-evrp=/dev/stdout x.c
struct { char a[4], b[4]; } x;

static inline void f (const char *s, int n)
{
  for (int i = 0; i != n; ++i)     // warning (good)...
    x.a[i] = s[i];
}

void g (const char *s)
{
  f (s, 5);                       // ...but loop doesn't terminate
}

;; Function f (f, funcdef_no=0, decl_uid=1936, cgraph_uid=1, symbol_order=1)

;; 2 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2 3 4 5
;;
;; Loop 1
;;  header 4, latch 3
;;  depth 1, outer 0
;;  nodes: 4 3
;; 2 succs { 4 }
;; 3 succs { 4 }
;; 4 succs { 3 5 }
;; 5 succs { 1 }

Value ranges after Early VRP:

_1: sizetype [0, 4]
_2: const char * VARYING
_3: char VARYING
i_4: int [0, 4]
n_8(D): int VARYING
s_9(D): const char * VARYING
i_11: int [1, 5]


f (const char * s, int n)
{
  int i;
  sizetype _1;
  const char * _2;
  char _3;

  <bb 2> :
  goto <bb 4>; [INV]

  <bb 3> :
  _1 = (sizetype) i_4;
  _2 = s_9(D) + _1;
  _3 = *_2;
  x.a[i_4] = _3;
  i_11 = i_4 + 1;

  <bb 4> :
  # i_4 = PHI <0(2), i_11(3)>
  if (i_4 != n_8(D))
    goto <bb 3>; [INV]
  else
    goto <bb 5>; [INV]

  <bb 5> :
  return;

}



;; Function g (g, funcdef_no=1, decl_uid=1943, cgraph_uid=2, symbol_order=2)

;; 2 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2 3 4 5
;;
;; Loop 1
;;  header 4, latch 3
;;  depth 1, outer 0
;;  nodes: 4 3
;; 2 succs { 4 }
;; 3 succs { 4 }
;; 4 succs { 3 5 }
;; 5 succs { 1 }
x.c: In function ā€˜gā€™:
x.c:6:12: warning: iteration 4 invokes undefined behavior
[-Waggressive-loop-optimizations]
    6 |     x.a[i] = s[i];
      |     ~~~~~~~^~~~~~
x.c:5:3: note: within this loop
    5 |   for (int i = 0; i != n; ++i)     // warning (good)...
      |   ^~~

Value ranges after Early VRP:

s_2(D): const char * VARYING
i_4: int [0, 4]
_5: sizetype [0, 4]
_6: const char * VARYING
_7: char VARYING
i_8: int [1, 5]


Removing basic block 5
Merging blocks 4 and 3
g (const char * s)
{
  int i;
  sizetype _5;
  const char * _6;
  char _7;

  <bb 2> :

  <bb 3> :
  # i_4 = PHI <0(2), i_8(3)>
  _5 = (sizetype) i_4;
  _6 = s_2(D) + _5;
  _7 = *_6;
  x.a[i_4] = _7;
  i_8 = i_4 + 1;
  goto <bb 3>; [100.00%]

}

Reply via email to