Bug 58346 - ICE with SIGFPE at -O1 and above on x86_64-linux-gnu (affecting trunk, 4.8, 4.7, and 4.6)
Summary: ICE with SIGFPE at -O1 and above on x86_64-linux-gnu (affecting trunk, 4.8, 4...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: ---
Assignee: Marek Polacek
URL:
Keywords: accepts-invalid, ice-on-invalid-code
: 58345 (view as bug list)
Depends on:
Blocks: 58344
  Show dependency treegraph
 
Reported: 2013-09-07 04:31 UTC by Zhendong Su
Modified: 2014-01-23 19:19 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-09-09 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Zhendong Su 2013-09-07 04:31:23 UTC
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;
}
Comment 1 Mikael Pettersson 2013-09-08 08:13:45 UTC
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
Comment 2 Richard Biener 2013-09-09 08:29:07 UTC
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.
Comment 3 Richard Biener 2013-09-09 08:33:13 UTC
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).
Comment 4 Richard Biener 2013-09-09 08:34:29 UTC
*** Bug 58345 has been marked as a duplicate of this bug. ***
Comment 5 jsm-csl@polyomino.org.uk 2013-09-09 17:04:34 UTC
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.
Comment 6 rguenther@suse.de 2013-09-10 07:49:30 UTC
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).
Comment 7 jsm-csl@polyomino.org.uk 2013-09-10 22:22:02 UTC
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).
Comment 8 Marek Polacek 2014-01-10 16:27:00 UTC
I'll to try teach the C FE to give an error when subtracting two pointers to empty aggregates.
Comment 9 Marek Polacek 2014-01-17 10:15:32 UTC
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.  */
Comment 10 Marek Polacek 2014-01-17 10:19:25 UTC
Somewhat reduced:

struct U {};
static struct U b[1] = { };
extern void bar (struct U);

void
foo (void)
{
  bar (b[0]);
}

void
baz (void)
{
  foo ();
}
Comment 11 Marek Polacek 2014-01-17 14:52:27 UTC
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
Comment 12 Jeffrey A. Law 2014-01-17 17:06:11 UTC
Fixed by Marek's patch on the trunk.
Comment 13 Marek Polacek 2014-01-23 19:19:20 UTC
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