The following code causes an ICE when compiled with the current gcc trunk, 4.8, and 4.7 at -O1 and above (at only -O1 for 4.6) on x86_64-linux (both 32-bit and 64-bit modes). This should be related to 58345 (the backtraces are almost identical), but affects also 4.6 and 4.7 as well as more optimization levels. $ gcc-trunk -v Using built-in specs. COLLECT_GCC=gcc-trunk COLLECT_LTO_WRAPPER=/usr/local/gcc-trunk/libexec/gcc/x86_64-unknown-linux-gnu/4.9.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: ../gcc-trunk/configure --enable-languages=c,c++,objc,obj-c++,fortran,lto --with-gmp=/usr/local/gcc-trunk --with-mpfr=/usr/local/gcc-trunk --with-mpc=/usr/local/gcc-trunk --with-cloog=/usr/local/gcc-trunk --prefix=/usr/local/gcc-trunk Thread model: posix gcc version 4.9.0 20130906 (experimental) [trunk revision 202308] (GCC) $ gcc-trunk -O0 -c small.c $ gcc-trunk -O1 -c small.c small.c: In function ‘main’: small.c:20:5: internal compiler error: Floating point exception int main () ^ 0x924b2f crash_signal ../../gcc-trunk/gcc/toplev.c:335 0x77ecd3 fold_array_ctor_reference ../../gcc-trunk/gcc/gimple-fold.c:2816 0x77ecd3 fold_ctor_reference ../../gcc-trunk/gcc/gimple-fold.c:2964 0x7827d2 fold_const_aggregate_ref_1(tree_node*, tree_node* (*)(tree_node*)) ../../gcc-trunk/gcc/gimple-fold.c:3066 0x78443b fold_const_aggregate_ref ../../gcc-trunk/gcc/gimple-fold.c:3088 0x78443b maybe_fold_reference ../../gcc-trunk/gcc/gimple-fold.c:272 0x784df6 gimple_fold_call ../../gcc-trunk/gcc/gimple-fold.c:1091 0x784df6 fold_stmt_1 ../../gcc-trunk/gcc/gimple-fold.c:1200 0x9763c9 fold_marked_statements ../../gcc-trunk/gcc/tree-inline.c:4380 0x983404 optimize_inline_calls(tree_node*) ../../gcc-trunk/gcc/tree-inline.c:4475 0xd85fa3 inline_transform(cgraph_node*) ../../gcc-trunk/gcc/ipa-inline-transform.c:436 0x880e6f execute_one_ipa_transform_pass ../../gcc-trunk/gcc/passes.c:2039 0x880e6f execute_all_ipa_transforms() ../../gcc-trunk/gcc/passes.c:2079 0x636160 expand_function ../../gcc-trunk/gcc/cgraphunit.c:1702 0x63809d expand_all_functions ../../gcc-trunk/gcc/cgraphunit.c:1814 0x63809d compile() ../../gcc-trunk/gcc/cgraphunit.c:2151 0x638729 finalize_compilation_unit() ../../gcc-trunk/gcc/cgraphunit.c:2228 0x516813 c_write_global_declarations() ../../gcc-trunk/gcc/c/c-decl.c:10125 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <http://gcc.gnu.org/bugs.html> for instructions. $ ----------------------------------------- struct U {}; static struct U b[1] = { }; int a, **c, d, *e, f; extern void bar (int, int, int, struct U); extern void foobar (int, int, int); extern int baz (int, int); static void foo () { bar (d, 0, 0, b[0]); foobar (0 >= f, 0, 0); **c = 0 == a; baz (**c, 0); baz (0, *e); *e = baz (0, 0); } int main () { foo (); return 0; }
Crashes with division-by-zero in the exact same spot as the PR58345 test case does. However this test case also crashes 4.7 and 4.6. Program received signal SIGFPE, Arithmetic exception. 0x00000000005e2448 in fold_array_ctor_reference (ctor=0x7ffff7627ca8, ctor=0x7ffff7627ca8, from_decl=0x7ffff7535be0, size=0, offset=0, type=0x7ffff7645540) at /mnt/scratch/gcc-4.9-20130901/gcc/gimple-fold.c:2816 2816 inner_offset = offset % (elt_size.to_uhwi () * BITS_PER_UNIT); (gdb) list 2811 if (index_type) 2812 access_index = access_index.ext (TYPE_PRECISION (index_type), 2813 TYPE_UNSIGNED (index_type)); 2814 2815 /* And offset within the access. */ 2816 inner_offset = offset % (elt_size.to_uhwi () * BITS_PER_UNIT); 2817 2818 /* See if the array field is large enough to span whole access. We do not 2819 care to fold accesses spanning multiple array indexes. */ 2820 if (inner_offset + size > elt_size.to_uhwi () * BITS_PER_UNIT) (gdb) print elt_size $1 = {low = 0, high = 0} (gdb) q
I believe the following should be invalid C struct U {}; static struct U b[1] = { }; U is a zero-sized struct and b is an array built from it. This array cannot fulfil the basic array index operation requirements unless the element size is bumped to one.
I wonder what struct U {}; static struct U b[6]; int foo (struct U *p, struct U *q) { return q - p; } int main() { return foo (&b[0], &b[4]); } is expected to do. It raises a division by zero exception at runtime (that's definitely a FE bug). That's either wrong-code or the same issue (not valid GNU C).
*** Bug 58345 has been marked as a duplicate of this bug. ***
I think some of the uses of the zero-size-objects extension are ones for which making an array of such objects is reasonable, but it makes sense to give an error for trying to subtract pointers to such objects.
On Mon, 9 Sep 2013, joseph at codesourcery dot com wrote: > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58346 > > --- Comment #5 from joseph at codesourcery dot com <joseph at codesourcery dot com> --- > I think some of the uses of the zero-size-objects extension are ones for > which making an array of such objects is reasonable, but it makes sense to > give an error for trying to subtract pointers to such objects. A similar (runtime) error can be provoked by subtracting pointers to array elements of variable size that happen to have zero size at runtime. This all seems to be a can of worms which I'd rather shield the middle-end from. For example we assume that a[0] and a[1] never alias. Can we at least make arrays of zero-sized elements trigger undefined behavior in our extension documentation? We probably can paper over the ICEs as they occur (testing coverage is very weak of course).
On Tue, 10 Sep 2013, rguenther at suse dot de wrote: > A similar (runtime) error can be provoked by subtracting pointers > to array elements of variable size that happen to have zero size > at runtime. Yes, that needs to be undefined at runtime. > This all seems to be a can of worms which I'd rather shield the > middle-end from. For example we assume that a[0] and a[1] never > alias. As I noted in bug 57725, code using zero-size objects should not care about whether their addresses compare equal - and any other consequence of a non-aliasing deduction shouldn't matter (given that stores to such objects will store zero bytes and reads from them will read zero bytes). > Can we at least make arrays of zero-sized elements trigger undefined > behavior in our extension documentation? We probably can paper > over the ICEs as they occur (testing coverage is very weak of course). It's specifically the subtraction of pointers that needs to be undefined. I'm doubtful about making such arrays undefined in the absence of such subtraction. Uses of zero-size objects are e.g. for when an object may be empty for some configurations of a program but not others (depending on whether a lock object is needed in that configuration, say), and it seems plausible someone might have an array of such conditionally zero-size objects, each corresponding to an element of another array (if there's a reason why using a single array of structs isn't appropriate).
I'll to try teach the C FE to give an error when subtracting two pointers to empty aggregates.
And to actually fix this bug, the following should be enough... --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -2940,7 +2940,8 @@ fold_array_ctor_reference (tree type, tree ctor, be larger than size of array element. */ if (!TYPE_SIZE_UNIT (type) || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST - || elt_size.slt (tree_to_double_int (TYPE_SIZE_UNIT (type)))) + || elt_size.slt (tree_to_double_int (TYPE_SIZE_UNIT (type))) + || elt_size.is_zero ()) return NULL_TREE; /* Compute the array index we look for. */
Somewhat reduced: struct U {}; static struct U b[1] = { }; extern void bar (struct U); void foo (void) { bar (b[0]); } void baz (void) { foo (); }
Author: mpolacek Date: Fri Jan 17 14:51:56 2014 New Revision: 206715 URL: http://gcc.gnu.org/viewcvs?rev=206715&root=gcc&view=rev Log: PR c/58346 * gimple-fold.c (fold_array_ctor_reference): Don't fold if element size is zero. testsuite/ * gcc.dg/pr58346.c: New test. Added: trunk/gcc/testsuite/gcc.dg/pr58346.c Modified: trunk/gcc/ChangeLog trunk/gcc/gimple-fold.c trunk/gcc/testsuite/ChangeLog
Fixed by Marek's patch on the trunk.
Author: mpolacek Date: Thu Jan 23 19:18:49 2014 New Revision: 207004 URL: http://gcc.gnu.org/viewcvs?rev=207004&root=gcc&view=rev Log: PR c/58346 c-family/ * c-common.c (pointer_to_zero_sized_aggr_p): New function. * c-common.h: Declare it. cp/ * typeck.c (pointer_diff): Give an error on arithmetic on pointer to an empty aggregate. c/ * c-typeck.c (pointer_diff): Give an error on arithmetic on pointer to an empty aggregate. testsuite/ * c-c++-common/pr58346-1.c: New test. * c-c++-common/pr58346-2.c: New test. * c-c++-common/pr58346-3.c: New test. Added: trunk/gcc/testsuite/c-c++-common/pr58346-1.c trunk/gcc/testsuite/c-c++-common/pr58346-2.c trunk/gcc/testsuite/c-c++-common/pr58346-3.c Modified: trunk/gcc/c-family/ChangeLog trunk/gcc/c-family/c-common.c trunk/gcc/c-family/c-common.h trunk/gcc/c/ChangeLog trunk/gcc/c/c-typeck.c trunk/gcc/cp/ChangeLog trunk/gcc/cp/typeck.c trunk/gcc/testsuite/ChangeLog