aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2015-11-03 18:53:19 +0000
committerMartin Sebor <msebor@redhat.com>2015-11-03 18:53:19 +0000
commit4ff05b782ba3b3a185263705daf07c75894ae124 (patch)
tree401facc539421f9aa5dc9e0dcaff8a9691d3412e
parentaa13e93c188d0c5030d7add7e90f10085d4eb47d (diff)
PR c++-common/67882
* c-family/c-common.h (fold_offsetof_1): Add argument. * c-family/c-common.c (fold_offsetof_1): Diagnose more invalid offsetof expressions that reference elements past the end of an array. * c-c++-common/builtin-offsetof-2.c: New test. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@229717 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/c-family/ChangeLog8
-rw-r--r--gcc/c-family/c-common.c15
-rw-r--r--gcc/c-family/c-common.h2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/c-c++-common/builtin-offsetof-2.c217
5 files changed, 239 insertions, 8 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 7f56722ac66..32a13c07689 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,11 @@
+2015-11-03 Bernd Schmidt <bschmidt@redhat.com>
+
+ PR c++-common/67882
+ * c-family/c-common.h (fold_offsetof_1): Add argument.
+ * c-family/c-common.c (fold_offsetof_1): Diagnose more invalid
+ offsetof expressions that reference elements past the end of
+ an array.
+
2015-11-03 Thomas Schwinge <thomas@codesourcery.com>
Chung-Lin Tang <cltang@codesourcery.com>
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index c87704baf35..de5f8b6cbdf 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -10631,11 +10631,11 @@ c_common_to_target_charset (HOST_WIDE_INT c)
traditional rendering of offsetof as a macro. Return the folded result. */
tree
-fold_offsetof_1 (tree expr)
+fold_offsetof_1 (tree expr, enum tree_code ctx)
{
tree base, off, t;
-
- switch (TREE_CODE (expr))
+ tree_code code = TREE_CODE (expr);
+ switch (code)
{
case ERROR_MARK:
return expr;
@@ -10659,7 +10659,7 @@ fold_offsetof_1 (tree expr)
return TREE_OPERAND (expr, 0);
case COMPONENT_REF:
- base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0), code);
if (base == error_mark_node)
return base;
@@ -10676,7 +10676,7 @@ fold_offsetof_1 (tree expr)
break;
case ARRAY_REF:
- base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0), code);
if (base == error_mark_node)
return base;
@@ -10691,8 +10691,9 @@ fold_offsetof_1 (tree expr)
&& !tree_int_cst_equal (upbound,
TYPE_MAX_VALUE (TREE_TYPE (upbound))))
{
- upbound = size_binop (PLUS_EXPR, upbound,
- build_int_cst (TREE_TYPE (upbound), 1));
+ if (ctx != ARRAY_REF && ctx != COMPONENT_REF)
+ upbound = size_binop (PLUS_EXPR, upbound,
+ build_int_cst (TREE_TYPE (upbound), 1));
if (tree_int_cst_lt (upbound, t))
{
tree v;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 6a381f23435..0da4b2e87c8 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1029,7 +1029,7 @@ extern bool c_dump_tree (void *, tree);
extern void verify_sequence_points (tree);
-extern tree fold_offsetof_1 (tree);
+extern tree fold_offsetof_1 (tree, tree_code ctx = ERROR_MARK);
extern tree fold_offsetof (tree);
/* Places where an lvalue, or modifiable lvalue, may be required.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 829e0a8f500..708b9d4381f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2015-11-03 Martin Sebor <msebor@redhat.com>
+
+ PR c++-common/67882
+ * c-c++-common/builtin-offsetof-2.c: New test.
+
2015-11-03 Dominique d'Humieres <dominiq@lps.ens.fr>
PR fortran/67982
diff --git a/gcc/testsuite/c-c++-common/builtin-offsetof-2.c b/gcc/testsuite/c-c++-common/builtin-offsetof-2.c
new file mode 100644
index 00000000000..f943dde05f7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-offsetof-2.c
@@ -0,0 +1,217 @@
+// { dg-options "-Warray-bounds" }
+// { dg-do compile }
+
+// Test case exercising pr c/67882 - surprising offsetof result
+// on an invalid array member without diagnostic.
+
+typedef struct A1 {
+ char a1[1];
+ char c;
+} A1;
+
+typedef struct A1_x_2 {
+ char a1[1];
+ char a[][2];
+} A1_x_2;
+
+typedef struct A1_1_x {
+ char a1_1[1][1];
+ char a[];
+} A1_1_x;
+
+typedef struct Ax_2_3 {
+ int i;
+ char a_x_2_3[][2][3];
+} Ax_2_3;
+
+typedef struct A1_1 {
+ char a1_1[1][1];
+ char c;
+} A1_1;
+
+typedef struct B {
+ A1_1 a2_3[2][3];
+ char a1_1[3][5];
+ char a[];
+} B;
+
+// Structures with members that contain flexible array members are
+// an extension accepted by GCC.
+typedef struct C {
+ A1_1_x a5_7 [5][7];
+ int a;
+} C;
+
+// Structs with a "fake" flexible array member (a GCC extension).
+typedef struct FA0 {
+ int i;
+ char a0 [0];
+} FA0;
+
+typedef struct FA1 {
+ int i;
+ char a1 [1];
+} FA1;
+
+typedef struct FA3 {
+ int i;
+ char a3 [3];
+} FA3;
+
+// A "fake" multidimensional flexible array member.
+typedef struct FA5_7 {
+ int i;
+ char a5_7 [5][7];
+} FA5_7;
+
+static void test (void)
+{
+ // Verify that offsetof references to array elements past the end of
+ // the array member are diagnosed. As an extension, permit references
+ // to the element just past-the-end of the array.
+
+ int a[] = {
+ __builtin_offsetof (A1, a1), // valid
+ __builtin_offsetof (A1, a1 [0]), // valid
+
+ // The following expression is valid because it forms the equivalent
+ // of an address pointing just past the last element of the array.
+ __builtin_offsetof (A1, a1 [1]), // valid
+
+ __builtin_offsetof (A1, a1 [2]), // { dg-warning "index" }
+
+ __builtin_offsetof (A1_x_2, a1), // valid
+ __builtin_offsetof (A1_x_2, a1 [0]), // valid
+ __builtin_offsetof (A1_x_2, a1 [1]), // valid
+ __builtin_offsetof (A1_x_2, a1 [2]), // { dg-warning "index" }
+
+ __builtin_offsetof (A1_x_2, a), // valid
+ __builtin_offsetof (A1_x_2, a [0]), // valid
+ __builtin_offsetof (A1_x_2, a [1]), // valid
+ __builtin_offsetof (A1_x_2, a [99]), // valid
+
+ __builtin_offsetof (A1_x_2, a), // valid
+ __builtin_offsetof (A1_x_2, a [0][0]), // valid
+ __builtin_offsetof (A1_x_2, a [0][1]), // valid
+
+ // The following expression is valid because it forms the equivalent
+ // of an address pointing just past the last element of the first
+ // array.
+ __builtin_offsetof (A1_x_2, a [0][2]), // valid
+
+ // Unlike the case above, this is invalid since it refers to an element
+ // past one one just-past-the-end in A[][2].
+ __builtin_offsetof (A1_x_2, a [0][3]), // { dg-warning "index" }
+
+ __builtin_offsetof (A1_x_2, a [1][0]), // valid
+ __builtin_offsetof (A1_x_2, a [1][1]), // valid
+ __builtin_offsetof (A1_x_2, a [1][2]), // valid
+ __builtin_offsetof (A1_x_2, a [99][0]), // valid
+ __builtin_offsetof (A1_x_2, a [99][1]), // valid
+ __builtin_offsetof (A1_x_2, a [99][2]), // valid
+
+ __builtin_offsetof (A1_1_x, a), // valid
+ __builtin_offsetof (A1_1_x, a [0]), // valid
+ __builtin_offsetof (A1_1_x, a [1]), // valid
+ __builtin_offsetof (A1_1_x, a [99]), // valid
+
+ __builtin_offsetof (A1_1_x, a1_1 [0][0]), // valid
+ __builtin_offsetof (A1_1_x, a1_1 [0][1]), // valid
+ __builtin_offsetof (A1_1_x, a1_1 [0][2]), // { dg-warning "index" }
+ __builtin_offsetof (A1_1_x, a1_1 [1][0]), // { dg-warning "index" }
+ __builtin_offsetof (A1_1_x, a1_1 [1][1]), // { dg-warning "index" }
+
+ __builtin_offsetof (Ax_2_3, a_x_2_3 [0][1][3]), // valid
+ __builtin_offsetof (Ax_2_3, a_x_2_3 [0][1][4]), // { dg-warning "index" }
+ __builtin_offsetof (Ax_2_3, a_x_2_3 [0][2]), // valid
+ __builtin_offsetof (Ax_2_3, a_x_2_3 [0][2][0]), // { dg-warning "index" }
+
+ __builtin_offsetof (B, a2_3 [0][0].c), // valid
+ __builtin_offsetof (B, a2_3 [0][0].a1_1 [0][0]), // valid
+ __builtin_offsetof (B, a2_3 [1][3]), // valid
+ __builtin_offsetof (B, a2_3 [1][4]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [0][0].a1_1 [0][1]), // valid
+ __builtin_offsetof (B, a2_3 [0][0].a1_1 [0][2]), // { dg-warning "index" }
+
+ __builtin_offsetof (B, a2_3 [0][0].a1_1 [1][0]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [0][0].a1_1 [1][1]), // { dg-warning "index" }
+
+ __builtin_offsetof (B, a2_3 [1][2].a1_1 [0][0]), // valid
+
+ // Forming an offset to the just-past-end element is valid.
+ __builtin_offsetof (B, a2_3 [1][2].a1_1 [0][1]), // valid
+ __builtin_offsetof (B, a2_3 [1][2].a1_1 [1][0]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [1][2].a1_1 [1][1]), // { dg-warning "index" }
+
+ // Forming an offset to the just-past-end element is valid.
+ __builtin_offsetof (B, a2_3 [1][3]), // valid
+ // ...but these are diagnosed because they dereference a just-past-the-end
+ // element.
+ __builtin_offsetof (B, a2_3 [1][3].a1_1 [0][0]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [1][3].a1_1 [0][0]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [1][3].a1_1 [0][1]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [1][3].a1_1 [1][0]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [1][3].a1_1 [1][1]), // { dg-warning "index" }
+
+ // Analogous to the case above, these are both diagnosed because they
+ // dereference just-past-the-end elements of the a2_3 array.
+ __builtin_offsetof (B, a2_3 [1][3].c), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [1][3].c), // { dg-warning "index" }
+
+ // The following are all invalid because of the reference to a2_3[2].
+ __builtin_offsetof (B, a2_3 [2][0].a1_1 [0][0]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [2][0].a1_1 [0][1]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [2][0].a1_1 [1][0]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [2][0].a1_1 [1][1]), // { dg-warning "index" }
+ __builtin_offsetof (B, a2_3 [2][0].c), // { dg-warning "index" }
+
+ __builtin_offsetof (C, a5_7 [4][6]),
+ __builtin_offsetof (C, a5_7 [4][6].a),
+ __builtin_offsetof (C, a5_7 [4][6].a [0]),
+ __builtin_offsetof (C, a5_7 [4][6].a [99]),
+
+ __builtin_offsetof (C, a5_7 [4][7]), // valid
+ // Diagnose the following even though the object whose offset is
+ // computed is a flexible array member.
+ __builtin_offsetof (C, a5_7 [4][7].a), // { dg-warning "index" }
+ __builtin_offsetof (C, a5_7 [4][7].a [0]), // { dg-warning "index" }
+ __builtin_offsetof (C, a5_7 [4][7].a [99]), // { dg-warning "index" }
+
+ // Verify that no diagnostic is issued for offsetof expressions
+ // involving structs where the array has a rank of 1 and is the last
+ // member (e.g., those are treated as flexible array members).
+ __builtin_offsetof (FA0, a0 [0]),
+ __builtin_offsetof (FA0, a0 [1]),
+ __builtin_offsetof (FA0, a0 [99]),
+
+ __builtin_offsetof (FA1, a1 [0]),
+ __builtin_offsetof (FA1, a1 [1]),
+ __builtin_offsetof (FA1, a1 [99]),
+
+ __builtin_offsetof (FA3, a3 [0]),
+ __builtin_offsetof (FA3, a3 [3]),
+ __builtin_offsetof (FA3, a3 [99]),
+
+ __builtin_offsetof (FA5_7, a5_7 [0][0]),
+
+ // Unlike one-dimensional arrays, verify that out-of-bounds references
+ // to "fake" flexible arrays with rank of 2 and greater are diagnosed.
+
+ // The following are valid because they compute the offset of just past
+ // the end of each of the a5_7[0] and a5_7[1] arrays.
+ __builtin_offsetof (FA5_7, a5_7 [0][7]), // valid
+ __builtin_offsetof (FA5_7, a5_7 [1][7]), // valid
+
+ // The following two are accepted as an extesion (because a5_7 is
+ // treated as a flexible array member).
+ __builtin_offsetof (FA5_7, a5_7 [5][0]), // extension
+ __builtin_offsetof (FA5_7, a5_7 [5][7]), // extension
+
+ // The following are invalid since in both cases they denote an element
+ // that's beyond just-past-the-end of the array.
+ __builtin_offsetof (FA5_7, a5_7 [0][8]), // { dg-warning "index" }
+ __builtin_offsetof (FA5_7, a5_7 [6][8]) // { dg-warning "index" }
+ };
+
+ (void)&a;
+}