Patchwork RFA: PATCH to get_inner_reference for c++/57793

login
register
mail settings
Submitter Jason Merrill
Date July 9, 2013, 6:02 a.m.
Message ID <51DBA771.3060807@redhat.com>
Download mbox | patch
Permalink /patch/257635/
State New
Headers show

Comments

Jason Merrill - July 9, 2013, 6:02 a.m.
This PR isn't really a C++ issue; it affects C as well, and presumably 
all other languages.  A comment a few lines down says

/* Avoid returning a negative bitpos as this may wreak havoc later.  */

but we were failing to avoid that in this case.

Tested x86_64-pc-linux-gnu.  OK for trunk/4.8?
Eric Botcazou - July 10, 2013, 8:24 a.m.
> This PR isn't really a C++ issue; it affects C as well, and presumably
> all other languages.  A comment a few lines down says
> 
> /* Avoid returning a negative bitpos as this may wreak havoc later.  */
> 
> but we were failing to avoid that in this case.
> 
> Tested x86_64-pc-linux-gnu.  OK for trunk/4.8?

Don't we want to error out instead of silently accepting this though?  You 
could call valid_constant_size_p at the beginning of the block for example.

The idea behind the existing trick is that the reference is within the bounds 
of the base object, i.e. the global offset (offset<<3 + bitpos) is positive, 
but the bitpos part is negative, so we rearrange it into ((offset-c>>3)<<3 + 
(bitpos+c)).  Here the global offset is negative because it has overflowed so 
I'm not sure the rearrangement makes any sense.

Patch

commit 168f0f28cf3986d0e067b640031a8baaee2d09a4
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jul 9 00:06:51 2013 -0400

    	PR c++/57793
    	* expr.c (get_inner_reference): Avoid returning a negative bitpos.

diff --git a/gcc/expr.c b/gcc/expr.c
index 923f59b..bbec492 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6733,7 +6733,7 @@  get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
       tem = tem.sext (TYPE_PRECISION (sizetype));
       tem = tem.lshift (BITS_PER_UNIT == 8 ? 3 : exact_log2 (BITS_PER_UNIT));
       tem += bit_offset;
-      if (tem.fits_shwi ())
+      if (tem.fits_shwi () && !tem.is_negative())
 	{
 	  *pbitpos = tem.to_shwi ();
 	  *poffset = offset = NULL_TREE;
diff --git a/gcc/testsuite/c-c++-common/pr57793.c b/gcc/testsuite/c-c++-common/pr57793.c
new file mode 100644
index 0000000..7858a27
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr57793.c
@@ -0,0 +1,23 @@ 
+/* PR c++/57793 */
+
+struct A { unsigned a : 1; unsigned b : 1; };
+struct B
+{
+  unsigned char c[0x40000000];
+  unsigned char d[0x40000ff0];
+  struct A e;
+};
+
+void *foo (struct B *p)
+{
+  if (p->e.a)
+    return (void *) 0;
+  p->e.b = 1;
+  return p->c;
+}
+
+void
+bar (struct B *p)
+{
+  foo (p);
+}