This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [RFA] PR c++/38699
- From: Dodji Seketeli <dodji at redhat dot com>
- To: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Tue, 3 Nov 2009 00:25:20 +0100
- Subject: Re: [RFA] PR c++/38699
- References: <20091029171805.GJ25276@adjoa.torimasen.com> <4AEC9DC9.4080109@redhat.com> <20091102200916.GC12119@adjoa.torimasen.com> <4AEF50C9.3090301@redhat.com>
On Mon, Nov 02, 2009 at 04:36:09PM -0500, Jason Merrill wrote:
> Much like, though I'd avoid having the integer_zerop call in two places
> by stripping INDIRECT_REF and NOP_EXPR as appropriate. You don't even
> need to strip NOP_EXPR really, since integer_zerop does that. And once
> you're checking integer_zerop you might as well remove the recursion and
> INTEGER_CST case and return size_zero_node directly if it's correct.
Indeed. The whole thing looks much better now, thanks.
Here is the patch I am testing currently.
commit 2925962a5f75db70f2d1646bf8e142145a3a2aa6
Author: Dodji Seketeli <dodji@redhat.com>
Date: Thu Oct 29 10:50:57 2009 +0100
Fix PR c++/38699
gcc/ChangeLog:
PR c++/38699
* c-common.c (fold_offsetof_1): Issue errors when the member designator of
the offsetoff expression is not legitimate.
gcc/testsuite/ChangeLog:
* g++.dg/other/offsetof6.C: New test.
* g++.dg/other/offsetof7.C: Likewise.
* gcc.dg/torture/builtin-offsetof.c: Likewise.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 8a6d15b..b025516 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -8335,15 +8335,14 @@ fold_offsetof_1 (tree expr, tree stop_ref)
error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
return error_mark_node;
- case INTEGER_CST:
- gcc_assert (integer_zerop (expr));
- return size_zero_node;
-
case NOP_EXPR:
case INDIRECT_REF:
- base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
- gcc_assert (base == error_mark_node || base == size_zero_node);
- return base;
+ if (!integer_zerop (TREE_OPERAND (expr, 0)))
+ {
+ error ("cannot apply %<offsetof%> to a non constant address");
+ return error_mark_node;
+ }
+ return size_zero_node;
case COMPONENT_REF:
base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
@@ -8376,6 +8375,16 @@ fold_offsetof_1 (tree expr, tree stop_ref)
}
t = convert (sizetype, t);
off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+
+ /* Check if the offset goes beyond the upper bound of the array. */
+ {
+ tree nelts = array_type_nelts (TREE_TYPE (TREE_OPERAND (expr, 0)));
+ HOST_WIDE_INT index = int_cst_value (t);
+ if (index > int_cst_value (nelts))
+ warning (OPT_Warray_bounds,
+ "index %ld denotes an offset greater than size of %qT",
+ index, TREE_TYPE (TREE_OPERAND (expr, 0)));
+ }
break;
case COMPOUND_EXPR:
diff --git a/gcc/testsuite/g++.dg/other/offsetof6.C b/gcc/testsuite/g++.dg/other/offsetof6.C
new file mode 100644
index 0000000..2ddb9a2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/offsetof6.C
@@ -0,0 +1,30 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin PR c++/38699
+// { dg-options "-Warray-bounds" }
+// { dg-do compile }
+
+struct A
+{
+ const char *p;
+};
+
+struct B
+{
+ char p[10];
+ A a;
+};
+
+void
+f0 ()
+{
+ __builtin_offsetof(A, p); // OK
+ __builtin_offsetof(A, p[0]); // { dg-error "non constant address" }
+ __builtin_offsetof(B, p[0]); // OK
+ __builtin_offsetof(B, p[9]); // OK
+ __builtin_offsetof(B, p[10]); // { dg-warning "greater than size" }
+ __builtin_offsetof(B, a.p); // OK
+ __builtin_offsetof(B, p[0]); // OK
+ __builtin_offsetof(B, a.p[0]); // { dg-error "non constant address" }
+}
+
+
diff --git a/gcc/testsuite/g++.dg/other/offsetof7.C b/gcc/testsuite/g++.dg/other/offsetof7.C
new file mode 100644
index 0000000..b77d1b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/offsetof7.C
@@ -0,0 +1,26 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin PR c++/38699
+// { dg-do compile }
+
+template<class T>
+struct A
+{
+ const T *p;
+};
+
+struct B
+{
+ A<int> a;
+};
+
+template class A<char>;
+
+void
+f0 ()
+{
+ __builtin_offsetof(A<char>, p); // OK
+ __builtin_offsetof(A<char>, p[1]); // { dg-error "non constant address" }
+ __builtin_offsetof(B, a.p); // OK
+ __builtin_offsetof(B, a.p[1]); // { dg-error "non constant address" }
+}
+
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-offsetof.c b/gcc/testsuite/gcc.dg/torture/builtin-offsetof.c
new file mode 100644
index 0000000..0ab498a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/builtin-offsetof.c
@@ -0,0 +1,29 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin PR c++/38699
+// { dg-options "-Warray-bounds" }
+// { dg-do compile }
+
+struct A
+{
+ const char *p;
+};
+
+struct B
+{
+ char p[10];
+ struct A a;
+};
+
+void
+f0 ()
+{
+ __builtin_offsetof(struct A, p); // OK
+ __builtin_offsetof(struct A, p[0]); // { dg-error "non constant address" }
+ __builtin_offsetof(struct B, p[0]); // OK
+ __builtin_offsetof(struct B, p[9]); // OK
+ __builtin_offsetof(struct B, p[10]); // { dg-warning "greater than size" }
+ __builtin_offsetof(struct B, a.p); // OK
+ __builtin_offsetof(struct B, p[0]); // OK
+ __builtin_offsetof(struct B, a.p[0]); // { dg-error "non constant address" }
+}
+