access_ref::add_offset() works hard to restore the property that the lower bound of a range is less than or equal to its upper bound. But by capping the upper bound to at most PTRDIFF_MAX without also considering the lower bound, it allows the latter to exceed the value of the former, thus violating the very postcondition it aims to guarantee.
To correct this oversight I have committed the attached patch as an obvious fix. Tested on x86_64-linux. Martin
PR middle-end/97556 - ICE on excessively large index into a multidimensional array gcc/ChangeLog: PR middle-end/97556 * builtins.c (access_ref::add_offset): Cap offset lower bound to at most the the upper bound. gcc/testsuite/ChangeLog: PR middle-end/97556 * gcc.dg/Warray-bounds-70.c: New test. diff --git a/gcc/builtins.c b/gcc/builtins.c index 3a3eb5562df..da25343beb1 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -321,7 +321,13 @@ void access_ref::add_offset (const offset_int &min, const offset_int &max) offrng[1] = maxoff; offset_int absmax = wi::abs (max); if (offrng[0] < absmax) - offrng[0] += min; + { + offrng[0] += min; + /* Cap the lower bound at the upper (set to MAXOFF above) + to avoid inadvertently recreating an inverted range. */ + if (offrng[1] < offrng[0]) + offrng[0] = offrng[1]; + } else offrng[0] = 0; } diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-70.c b/gcc/testsuite/gcc.dg/Warray-bounds-70.c new file mode 100644 index 00000000000..087e255599c --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-70.c @@ -0,0 +1,18 @@ +/* PR middle-end/97556 - ICE on excessively large index into a multidimensional + array + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +#define SIZE_MAX __SIZE_MAX__ + +typedef __SIZE_TYPE__ size_t; + +char a[1][3]; + +void f (int c) +{ + size_t i = c ? SIZE_MAX / 2 : SIZE_MAX; + a[i][0] = 0; // { dg-warning "\\\[-Warray-bounds" } +} + +// { dg-prune-output "\\\[-Wstringop-overflow=" }