Bug 82612 - missing -Warray-bounds on a non-zero offset from the address of a non-array object
Summary: missing -Warray-bounds on a non-zero offset from the address of a non-array o...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 8.0
: P3 normal
Target Milestone: 10.0
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Warray-bounds
  Show dependency treegraph
 
Reported: 2017-10-19 03:17 UTC by Martin Sebor
Modified: 2019-11-05 16:23 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-11-03 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2017-10-19 03:17:55 UTC
More testing of my -Warray-bounds patch for pr82588 et al. exposed a missing warning on the following corner case (and similar cases like it).

$ cat a.c && gcc -O2 -S -Warray-bounds a.c
int g (int i)
{
  int *p = &i;

  return p[2];
}

To detect this the implementation could check the operand of the address-of operator and trigger if it's a non-array object.  It should even be possible to detect the out-of-bounds index in the following:

int a[3];
int b[5];

int f (int i)
{
  int *p = i < 0 ? a : b;

  return p[7];
}
Comment 1 Richard Biener 2017-10-19 07:19:23 UTC
But we are not even having an ARRAY_REF in the IL ...

So try

int g (int i)
{
  int (*p)[2] = (int (*)[2])&i;

  return (*p)[2];
}

where we also do not warn.  Or the VLA variant:

int g (int i, int n)
{
  int (*p)[n] = (int (*)[n])&i;

  return (*p)[2];
}

Basically the warning code blindly trusts the ARRAY_TYPE domain even if
there's an underlying decl where that array wouldn't fit.  So the warning
you are requesting is more an out-of-bound object access in general.

To warn for this substitute each variable offset with its minimum range
value, call get_ref_base_and_extent and see if offset/size are within
the base object.
Comment 2 Martin Sebor 2017-10-20 02:01:17 UTC
I realize there's no ARRAY_REF but users unfamiliar with GCC internals don't, nor would they care.  I'm less concerned about code that defeats the type system by using casts (though it would be nice to diagnose those as well if possible).  What I think is important to try to diagnose is mistakes in otherwise good, clean code.  Here's another example:

  struct A { char a[4]; };
  struct B { struct A a[2]; };

  int f (struct B *b)
  {
    char *p = b[0].a[1].a;

    return p[13];   // invalid: MEM[(char *)b_2(D) + 17B];
  }

  int g (struct B *b)
  {
    char *p = b[1].a[1].a;

    return p[1];   // valid: MEM[(char *)b_2(D) + 17B];
  }

There's no way to diagnose this in tree-vrp.c because there's no way to distinguish the two MEM_REFs at that point (same as in pr82585).  This isn't a shortcoming of the warning code in tree-vrp.c  But it is a deficiency in the -Warray-bounds warning.  This coding bug could be detected before the pointer addition that still has access to the array bounds is folded into a MEM_REF (in tree-ssa-forwprop.c).
Comment 3 Martin Sebor 2019-11-03 22:35:23 UTC
The warning was enhanced in GCC 9.1 (r262893) to detect this bug, except that due to my own oversight it doesn't handle the PARAM_DECL case.  It's trivial to add it.  Let me take care of it for GCC 10.0.

$ cat pr82612.c && gcc -O2 -S -Wall pr82612.c
int i;
int f0 (void)
{ 
  int *p = &i;
  return p[2];   // -Warray-bounds (good)
}

int f1 (void)
{
  int i;
  int *p = &i;
  return p[2];   // -Warray-bounds (good)
}

int f2 (int i)
{
  int *p = &i;
  return p[2];   // missing -Warray-bounds
}
pr82612.c: In function ‘f0’:
pr82612.c:5:11: warning: array subscript 2 is outside array bounds of ‘int[1]’ [-Warray-bounds]
    5 |   return p[2];   // -Warray-bounds (good)
      |          ~^~~
pr82612.c:1:5: note: while referencing ‘i’
    1 | int i;
      |     ^
pr82612.c: In function ‘f1’:
pr82612.c:12:11: warning: array subscript 2 is outside array bounds of ‘int[1]’ [-Warray-bounds]
   12 |   return p[2];   // -Warray-bounds (good)
      |          ~^~~
pr82612.c:10:7: note: while referencing ‘i’
   10 |   int i;
      |       ^
Comment 4 Martin Sebor 2019-11-05 16:21:15 UTC
Author: msebor
Date: Tue Nov  5 16:20:44 2019
New Revision: 277851

URL: https://gcc.gnu.org/viewcvs?rev=277851&root=gcc&view=rev
Log:
PR middle-end/92341 - missing -Warray-bounds indexing past the end of a compound literal
PR middle-end/82612 - missing -Warray-bounds on a non-zero offset from the address of a non-array object

gcc/testsuite/ChangeLog:

	PR middle-end/92341
	PR middle-end/82612
	* g++.dg/warn/Warray-bounds-4.C: Adjust text of expected warning.
	* gcc.dg/Warray-bounds-53.c: New test.
	* gcc.dg/Warray-bounds-54.c: New test.

gcc/ChangeLog:

	PR middle-end/92341
	PR middle-end/82612
	* tree-sra.c (get_access_for_expr): Fail for out-of-bounds offsets.
	* tree-vrp.c (vrp_prop::check_array_ref): Correct index and text
	of message printed in a warning for empty arrays.
	(vrp_prop::check_mem_ref): Also handle function parameters and
	empty arrays.


Added:
    trunk/gcc/testsuite/gcc.dg/Warray-bounds-53.c
    trunk/gcc/testsuite/gcc.dg/Warray-bounds-54.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/g++.dg/warn/Warray-bounds-4.C
    trunk/gcc/tree-sra.c
    trunk/gcc/tree-vrp.c
Comment 5 Martin Sebor 2019-11-05 16:23:40 UTC
With r277851 check in, the PARM_DECL case is detected as well.