array subscript is below array bounds : false positive?
Ian Lance Taylor
iant@google.com
Tue Sep 15 14:56:00 GMT 2009
"Peter A. Felvegi" <petschy@praire-chicken.com> writes:
> I've run into this strange warning when compiling w/ optimization:
> gcc-4.3 -O2 -Werror -Wall -c -o t.o t.c
> cc1: warnings being treated as errors
> t.c: In function ‘foo’:
> t.c:25: error: array subscript is below array bounds
This question is appropriate for gcc-help@gcc.gnu.org, not
gcc@gcc.gnu.org. Please take any followups to gcc-help. Thanks.
> t.c is :
> ---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8----
> #define ASSERT(x) if (x) { } else { __asm__("int $0x03"); }
> #define SIZE 5
>
> char hnd[SIZE];
> char flg[SIZE];
>
> char crd();
> int idx(char);
> void set(int i, char v);
>
> #if 1
> void set(int i, char v)
> {
> ASSERT(i >=0 && i < SIZE);
> flg[i] = v;
> }
> #endif
>
>
> void foo()
> {
> char c = crd();
> int i = idx(0);
> ASSERT(i != -1);
> hnd[i] = c; // array subscript is below array bounds
> set(i, 1);
> }
> ---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8----
>
> Suppose that idx(c) returns the position of c in an array, an the
> return value of -1 means that c is not in the array. The assertion
> checks that.
>
> The funny thing is, if I change the source a bit, the warning goes away:
> 1) set '#if 1' to '#if 0' so that only the prototype of set() is visible
> 2) comment out the ASSERT() int set()
> 3) comment out ASSERT() just before the marked line
> 4) comment out set(i, 1) just after the marked line
>
> The warning is not present under -O2.
gcc is getting fooled because of your ASSERT macro. The optimizer is
pulling the reference to hnd[i] into the ASSERT branches, because it can
then optimize the reference knowing that i == -1. That is:
ASSERT (i != -1)
hnd[i] = c;
=>
if (i != -1) { } else { __asm__ (""); }
hnd[i] = c;
=>
if (i != -1) { hnd[i] = c; } else { __asm__ (""); hnd[-1] = c; }
You can avoid this kind of thing by telling gcc that your assert
condition does not return.
void assert_failure () __attribute__ ((noreturn, always_inline));
void assert_failure() { __asm__ ("int $0x03"); }
#define ASSERT(x) if (x) { } else { assert_failure(); }
Ian
More information about the Gcc
mailing list