GCC Bugzilla – Bug 45978
[4.6 Regression] bogus "array subscript is above array bounds" warning in extremely simple code with no loops
Last modified: 2013-04-12 16:17:49 UTC
Created attachment 22021 [details]
C++ source file illustrating bug
[I don't know if the "component:" field is correct, but there doesn't seem to be a "I don't know" option]
There are many bugs in gcc's bugzilla related to bogus array-bounds warnings, but most of them seem to involve loops and other situations that may need non-trivial analysis by the compiler.
However the attached C++ source file ("tt.cc") seems to be almost trivial; it contains no loops at all, and all array references use a constant (and valid) index, but it nonetheless elicits an "array subscript is above array bounds" warning from the compiler. As far as I can figure, the warning is bogus.
Compilation looks like:
$ g++-snapshot -O3 -S -Wall -Wextra tt.cc
tt.cc: In function 'Z test()':
tt.cc:15:21: warning: array subscript is above array bounds [-Warray-bounds]
$ g++-snapshot --version
g++ (Debian 20101009-1) 4.6.0 20101009 (experimental) [trunk revision 165234]
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
"g++-snapshot" just invokes g++ from Debian's gcc-snapshot package, which is a somewhat recent trunk snapshot.
["tt.cc" is as minimal as I can get it -- moving, eliminating, or changing any field in any of the structures seems to silence the warning.]
Confirmed. The vectorizer uses &MEM[(struct Y *)&<retval>].ar; as the
base address for the store to .c.x, .c.y, .c.z, .d.
Hmm, I'm not sure how to address this - we warn about the address-taking
operation which only at VRP time get's folded to &MEM[(struct Y *)&<retval>].ar
via maybe_fold_stmt_addition (which I only preserved to avoid some regressions
I don't remember anymore during mem-ref development).
Clearly even the first vectorized access spans more than the array (but we
could set TREE_NO_WARNING on the memory reference itself).
--- gimple-fold.c (revision 169917)
+++ gimple-fold.c (working copy)
@@ -212,6 +212,7 @@ maybe_fold_offset_to_array_ref (location
tree min_idx, idx, idx_type, elt_offset = integer_zero_node;
tree array_type, elt_type, elt_size;
+ tree no_warning = false;
/* If BASE is an ARRAY_REF, we can pick up another offset (this time
measured in units of the size of elements type) from that ARRAY_REF).
@@ -308,26 +309,34 @@ maybe_fold_offset_to_array_ref (location
should not be simplified into (*c) or tree-vrp will
- give false warnings.
- This is only an issue for multi-dimensional arrays. */
- if (TREE_CODE (elt_type) == ARRAY_TYPE
- && domain_type)
+ give false warnings. For multi-dimensional arrays
+ avoid this transformation, for one-dimensional arrays
+ set TREE_NO_WARNING on out-of-bound references. */
+ if (domain_type)
+ bool oob = false;
if (TYPE_MAX_VALUE (domain_type)
&& TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST
&& tree_int_cst_lt (TYPE_MAX_VALUE (domain_type), idx))
- return NULL_TREE;
+ oob = true;
else if (TYPE_MIN_VALUE (domain_type)
&& TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST
&& tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type)))
- return NULL_TREE;
+ oob = true;
else if (compare_tree_int (idx, 0) < 0)
+ oob = true;
+ if (oob)
+ if (TREE_CODE (elt_type) == ARRAY_TYPE)
+ no_warning = true;
tree t = build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE);
SET_EXPR_LOCATION (t, loc);
+ TREE_NO_WARNING (t) = no_warning;
fixes this but will cause us to omit all warnings for C array accesses
that are out-of-bounds:
FAIL: gcc.dg/Warray-bounds.c (test for warnings, line 59)
FAIL: gcc.dg/Warray-bounds.c (test for warnings, line 60)
FAIL: gcc.dg/Warray-bounds.c (test for warnings, line 65)
FAIL: gcc.dg/Warray-bounds.c (test for warnings, line 66)
FAIL: gcc.dg/Warray-bounds.c (test for warnings, line 72)
FAIL: gcc.dg/Warray-bounds.c (test for warnings, line 73)
In general I'd say we should not warn from VRP after loop opts, and
for address-taking operations we should have a distinct warning,
eventually looking at object sizes, not only type bounds.
This bug is a regression only because we now vectorize the testcase to
xorps %xmm0, %xmm0
movq %rdi, %rax
movlps %xmm0, (%rdi)
movhps %xmm0, 8(%rdi)
movlps %xmm0, 16(%rdi)
movlps %xmm0, 24(%rdi)
xorl %edx, %edx
movq %rdi, %rax
movl %edx, (%rdi)
movl %edx, 4(%rdi)
movl %edx, 8(%rdi)
movl %edx, 12(%rdi)
movl %edx, 16(%rdi)
movl %edx, 20(%rdi)
movl %edx, 24(%rdi)
movl %edx, 28(%rdi)
which is a good thing.
Eventually we can mitigate the problem from inside the vectorizer by
vect_p.7_13 = &MEM[(struct Y *)&<retval>].ar;
vect_p.7_13 = &<retval> + off
style initial addresses. Unfortunately that isn't very easy to do.
GCC 4.6.0 is being released, adjusting target milestone.
Hmm, I'm not getting this warning anymore ... is the bug fixed?
[version "g++ (Debian 20110519-1) 4.7.0 20110519 (experimental) [trunk revision 173903]"]
The bug was indeed worked around in VRP by making it use the CCP engine.
It now sees
MEM[(struct Y *)&<retval> + 16B] = vect_cst_.6_11;
instead of &MEM[(struct Y *)&<retval>].ar as a base which makes it not warn.
The vectorizer still uses that address as base though.
So I suppose we can say it's fixed in 4.7 by adjusting the pass that
emits the warning.
GCC 4.6.1 is being released.
Created attachment 25059 [details]
An obviously correct example that triggers the bug.
(In reply to comment #7)
> GCC 4.6.1 is being released.
I just searched for this problem due to a bug report that SWIG causes out of bounds array accesses: https://sourceforge.net/tracker/?func=detail&atid=101645&aid=3394790&group_id=1645
It turns out that the generated code is similar to the trivial example that I attached. Perhaps this makes it easier to track down the bug.
GCC 4.6.2 is being released.
GCC 4.6.3 is being released.
Created attachment 27800 [details]
Another failing testcase - reduced from xserver-xorg-input-mouse
The 4.6 branch has been closed, fixed in GCC 4.7.0.