User account creation filtered due to spam.

Bug 44300 - Spurious array subscript warning, &b[0] == &a[1] is not folded
Summary: Spurious array subscript warning, &b[0] == &a[1] is not folded
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.4.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2010-05-27 20:00 UTC by jmattson
Modified: 2010-05-29 00:34 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-05-28 17:51:52


Attachments
source code (115 bytes, text/plain)
2010-05-27 20:01 UTC, jmattson
Details

Note You need to log in before you can comment on or make changes to this bug.
Description jmattson 2010-05-27 20:00:26 UTC
In the following code, foo() properly guards the expression 'p[-1]' with a test that p is a pointer to an element of a[] other than the first element.  Yet, when gcc analyzes array subscripts, it raises a warning because foo() is used in a context where p points to the first element of b[].

Even if the compiler isn't sophisticated enough to optimize away the entire body of foo(), it should have enough information to determine that 'p[-1]' is valid in the context where it is used.  Instead, it complains:

x.c: In function ‘bar’:
x.c:7: warning: array subscript is below array bounds

----------------------------------------
int a[10], b[10];

static inline void
foo(int *p)
{
   if (p > a && p < a + 10) {
      p[-1] = 0;
   }
}

void
bar(void)
{
   foo(b);
}
----------------------------------------

% gcc -v -save-temps -c -O2 -Wall x.c
Using built-in specs.
Target: x86_64-suse-linux
Configured with: ../configure --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.4 --enable-ssp --disable-libssp --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --disable-libgcj --disable-libmudflap --with-slibdir=/lib64 --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-version-specific-runtime-libs --program-suffix=-4.4 --enable-linux-futex --without-system-libunwind --with-arch-32=i586 --with-tune=generic --build=x86_64-suse-linux
Thread model: posix
gcc version 4.4.1 [gcc-4_4-branch revision 150839] (SUSE Linux) 
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-O2' '-Wall' '-mtune=generic'
 /usr/lib64/gcc/x86_64-suse-linux/4.4/cc1 -E -quiet -v x.c -mtune=generic -Wall -O2 -fpch-preprocess -o x.i
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /usr/lib64/gcc/x86_64-suse-linux/4.4/include
 /usr/lib64/gcc/x86_64-suse-linux/4.4/include-fixed
 /usr/lib64/gcc/x86_64-suse-linux/4.4/../../../../x86_64-suse-linux/include
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-O2' '-Wall' '-mtune=generic'
 /usr/lib64/gcc/x86_64-suse-linux/4.4/cc1 -fpreprocessed x.i -quiet -dumpbase x.c -mtune=generic -auxbase x -O2 -Wall -version -o x.s
GNU C (SUSE Linux) version 4.4.1 [gcc-4_4-branch revision 150839] (x86_64-suse-linux)
	compiled by GNU C version 4.4.1 [gcc-4_4-branch revision 150839], GMP version 4.3.1, MPFR version 2.4.1-p5.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 7c58d9f1f1af203b4391f1c94895405a
x.c: In function ‘bar’:
x.c:7: warning: array subscript is below array bounds
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-O2' '-Wall' '-mtune=generic'
 /usr/lib64/gcc/x86_64-suse-linux/4.4/../../../../x86_64-suse-linux/bin/as -V -Qy -o x.o x.s
GNU assembler version 2.19.51 (x86_64-suse-linux) using BFD version (GNU Binutils; openSUSE 11.2) 2.19.51.20090527-10.26.4
COMPILER_PATH=/usr/lib64/gcc/x86_64-suse-linux/4.4/:/usr/lib64/gcc/x86_64-suse-linux/4.4/:/usr/lib64/gcc/x86_64-suse-linux/:/usr/lib64/gcc/x86_64-suse-linux/4.4/:/usr/lib64/gcc/x86_64-suse-linux/:/usr/lib64/gcc/x86_64-suse-linux/4.4/../../../../x86_64-suse-linux/bin/
LIBRARY_PATH=/usr/lib64/gcc/x86_64-suse-linux/4.4/:/usr/lib64/gcc/x86_64-suse-linux/4.4/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib64/gcc/x86_64-suse-linux/4.4/../../../../x86_64-suse-linux/lib/:/usr/lib64/gcc/x86_64-suse-linux/4.4/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-O2' '-Wall' '-mtune=generic'
Comment 1 jmattson 2010-05-27 20:01:37 UTC
Created attachment 20761 [details]
source code
Comment 2 Andrew Pinski 2010-05-27 20:03:56 UTC
"&b[0] > &a[0]" is not well defined in C or C++.  That is what it gets optimized to.
Comment 3 jmattson 2010-05-27 20:31:22 UTC
Admittedly, foo() makes some assumptions about alignment as originally written.  A more pedantic version is:

static inline void
foo(int *p)
{
   if (p >= a + 1 && p < a + 10) {
      p[-1] = 0;
   }
}

gcc still generates a warning with this version.

Even if a[] and b[] overlap, the guard clause ensures that the expression 'p[-1]' is within the bounds of array a[].
Comment 4 Richard Biener 2010-05-28 10:30:00 UTC
GCC sees at the point of the warning

 if (&b > &a && &b[0] < &a[10])
   b[-1] = 0;

and it cannot statically determine those comparisons.

So it warns (IMHO correctly).  This is very unlikely going to be fixed.
Comment 5 jmattson 2010-05-28 14:39:34 UTC
Can you recommend an elegant way to rewrite this code to avoid the warning?
Comment 6 Richard Biener 2010-05-28 14:44:43 UTC
Not really.  Comparing pointers that point to different objects invokes
undefined behavior anyway.

You could try

    --p;
    if (p >= a && p < a + 10) {
      *p = 0;
   }
Comment 7 jmattson 2010-05-28 15:55:44 UTC
So, you are saying that given an arbitrary pointer p, it is impossible to determine whether or not p points to an element of array a[], because comparing pointers to different objects is undefined?  I find that hard to believe, but I'm no standards lawyer.

Your suggested rewrite results in the same error.
Comment 8 Richard Biener 2010-05-28 16:40:30 UTC
(In reply to comment #7)
> So, you are saying that given an arbitrary pointer p, it is impossible to
> determine whether or not p points to an element of array a[], because comparing
> pointers to different objects is undefined?  I find that hard to believe, but
> I'm no standards lawyer.

6.5.8/5 says that (note it only applies to relational operators, not
equality operators).

> Your suggested rewrite results in the same error.

That's unfortunate.  The following doesn't warn for me (but make
sure it's an identity transform):

   if (p > a && p < a + 10) {
      a[p - a - 1] = 0;
   }
Comment 9 jmattson 2010-05-28 16:53:11 UTC
Okay.  What if we stick with equality operators, then?

static inline void
foo(int *p)
{
   if (p == a + 1 || p == a + 2) {
      p[-1] = 0;
   }
}

This code results in the same warning.
Comment 10 Richard Biener 2010-05-28 17:51:52 UTC
(In reply to comment #9)
> Okay.  What if we stick with equality operators, then?
> 
> static inline void
> foo(int *p)
> {
>    if (p == a + 1 || p == a + 2) {
>       p[-1] = 0;
>    }
> }
> 
> This code results in the same warning.

Yep.  That's because a and b might not bind locally and thus we do not
know whether &b[0] == &a[1].

We don't warn for -fno-common, but in this case we might still
optimize the comparison.

Confirmed for the testcase in comment #9.
Comment 11 Segher Boessenkool 2010-05-29 00:34:15 UTC
(In reply to comment #5)
> Can you recommend an elegant way to rewrite this code to avoid the warning?

static inline void
foo(int *p)
{
   if ((uintptr_t)p - (uintptr_t)(a + 1) < sizeof a - sizeof a[0]) {
      p[-1] = 0;
   }
}