"Peter A. Felvegi" <pets...@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-h...@gcc.gnu.org, not
g...@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

Reply via email to