Bug 96561 - missing warning for buffer overflow with negative offset
Summary: missing warning for buffer overflow with negative offset
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Warray-bounds Wstringop-overflow
  Show dependency treegraph
 
Reported: 2020-08-10 19:15 UTC by Martin Sebor
Modified: 2020-08-10 19:15 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2020-08-10 19:15:18 UTC
Only two of the four equivalent instances of buffer overflow in the test program  below are detected.  All four should be.

Even the member into which the store writes isn't mentioned, the store in 'MEM[(int *)p_1(D) + 3B] = 0' in the last two instances can be diagnosed based on the analysis that starting offset of the access, p_1(D) + 3B, points to one member of the struct while the ending offset, p_1(D) + 3B + sizeof (int), points to another.

$ cat t.c && gcc -O2 -S -Wall -Wextra -fdump-tree-vrp=/dev/stdout -xc++ t.c
void* operator new (__SIZE_TYPE__, void *p) { return p; }

struct S { int n; char a[0]; };

void f0 (struct S *p)
{
  new (&p->a[-1]) int ();    // -Wplacement-new (good)
}

void f1 (struct S *p)
{
  p->a[-1] = 0;              // -Warray-bounds (also good)
}

void f2 (struct S *p)
{
  char *q = p->a;
  q[-1] = 0;                   // no warning
}

void f3 (struct S *p)
{
  char *q = p->a;
  __builtin_memset (q - 1, 0, sizeof (int));   // no warning
}

t.c: In function ‘void f0(S*)’:
t.c:7:8: warning: placement new constructing an object of type ‘int’ and size ‘4’ in a region of type ‘char [0]’ and size ‘0’ [-Wplacement-new=]
    7 |   new (&p->a[-1]) int ();    // -Wplacement-new (good)
      |        ^~~~~~~~~

;; Function operator new (_ZnwmPv, funcdef_no=0, decl_uid=2337, cgraph_uid=1, symbol_order=0)

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

Value ranges after VRP:



operator new (long unsigned int D.2335, void * p)
{
  <bb 2> [local count: 1073741824]:
  return p_1(D);

}



;; Function operator new (_ZnwmPv, funcdef_no=0, decl_uid=2337, cgraph_uid=1, symbol_order=0)

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

Value ranges after VRP:



operator new (long unsigned int D.2335, void * p)
{
  <bb 2> [local count: 1073741824]:
  return p_1(D);

}



;; Function f0 (_Z2f0P1S, funcdef_no=1, decl_uid=2344, cgraph_uid=2, symbol_order=1)

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

Value ranges after VRP:



f0 (struct S * p)
{
  <bb 2> [local count: 1073741824]:
  MEM[(int *)p_1(D) + 3B] = 0;
  return;

}



;; Function f0 (_Z2f0P1S, funcdef_no=1, decl_uid=2344, cgraph_uid=2, symbol_order=1)

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

Value ranges after VRP:



f0 (struct S * p)
{
  <bb 2> [local count: 1073741824]:
  MEM[(int *)p_1(D) + 3B] = 0;
  return;

}



;; Function f1 (_Z2f1P1S, funcdef_no=2, decl_uid=2350, cgraph_uid=3, symbol_order=2)

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

Value ranges after VRP:



t.c: In function ‘void f1(S*)’:
t.c:12:10: warning: array subscript -1 is below array bounds of ‘char [0]’ [-Warray-bounds]
   12 |   p->a[-1] = 0;              // -Warray-bounds (also good)
      |   ~~~~~~~^
t.c:3:24: note: while referencing ‘S::a’
    3 | struct S { int n; char a[0]; };
      |                        ^
f1 (struct S * p)
{
  <bb 2> [local count: 1073741824]:
  p_2(D)->a[-1] = 0;
  return;

}



;; Function f1 (_Z2f1P1S, funcdef_no=2, decl_uid=2350, cgraph_uid=3, symbol_order=2)

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

Value ranges after VRP:



f1 (struct S * p)
{
  <bb 2> [local count: 1073741824]:
  p_2(D)->a[-1] = 0;
  return;

}



;; Function f2 (_Z2f2P1S, funcdef_no=3, decl_uid=2353, cgraph_uid=4, symbol_order=3)

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

Value ranges after VRP:



f2 (struct S * p)
{
  <bb 2> [local count: 1073741824]:
  MEM[(char *)p_1(D) + 3B] = 0;
  return;

}



;; Function f2 (_Z2f2P1S, funcdef_no=3, decl_uid=2353, cgraph_uid=4, symbol_order=3)

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

Value ranges after VRP:



f2 (struct S * p)
{
  <bb 2> [local count: 1073741824]:
  MEM[(char *)p_1(D) + 3B] = 0;
  return;

}



;; Function f3 (_Z2f3P1S, funcdef_no=4, decl_uid=2357, cgraph_uid=5, symbol_order=4)

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

Value ranges after VRP:

_1: char * [1B, +INF]
p_2(D): struct S * VARYING


f3 (struct S * p)
{
  char * _1;

  <bb 2> [local count: 1073741824]:
  _1 = &MEM <char> [(void *)p_2(D) + 3B];
  __builtin_memset (_1, 0, 4);
  return;

}



;; Function f3 (_Z2f3P1S, funcdef_no=4, decl_uid=2357, cgraph_uid=5, symbol_order=4)

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

Value ranges after VRP:

_1: char * [1B, +INF]
p_2(D): struct S * VARYING


f3 (struct S * p)
{
  char * _1;

  <bb 2> [local count: 1073741824]:
  _1 = &MEM <char> [(void *)p_2(D) + 3B];
  __builtin_memset (_1, 0, 4);
  return;

}