aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-03-08 13:37:21 -0700
committerMartin Sebor <msebor@redhat.com>2021-03-08 13:37:21 -0700
commitf3daa6c0fd8d79ae45eac2dd0f274da1aa71c958 (patch)
treeb3ab03035bc62990c57b38a1dccf441011dd1209 /gcc
parent7f5ff78ff3f971c11ec67f422b2fd34281db9123 (diff)
downloadgcc-f3daa6c0fd8d79ae45eac2dd0f274da1aa71c958.zip
gcc-f3daa6c0fd8d79ae45eac2dd0f274da1aa71c958.tar.gz
gcc-f3daa6c0fd8d79ae45eac2dd0f274da1aa71c958.tar.bz2
PR middle-end/98266 - bogus array subscript is partly outside array bounds on virtual inheritance
gcc/ChangeLog: PR middle-end/98266 * gimple-array-bounds.cc (inbounds_vbase_memaccess_p): New function. (array_bounds_checker::check_array_bounds): Call it. gcc/testsuite/ChangeLog: PR middle-end/98266 * g++.dg/warn/Warray-bounds-15.C: New test. * g++.dg/warn/Warray-bounds-18.C: New test. * g++.dg/warn/Warray-bounds-19.C: New test. * g++.dg/warn/Warray-bounds-20.C: New test. * g++.dg/warn/Warray-bounds-21.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gimple-array-bounds.cc52
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-15.C33
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-18.C167
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-19.C110
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-20.C68
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-21.C111
6 files changed, 540 insertions, 1 deletions
diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index d7fd2c7..54f3205 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -890,6 +890,50 @@ array_bounds_checker::check_addr_expr (location_t location, tree t)
}
}
+/* Return true if T is a reference to a member of a base class that's within
+ the bounds of the enclosing complete object. The function "hacks" around
+ problems discussed in pr98266 and pr97595. */
+
+static bool
+inbounds_vbase_memaccess_p (tree t)
+{
+ if (TREE_CODE (t) != COMPONENT_REF)
+ return false;
+
+ tree mref = TREE_OPERAND (t, 0);
+ if (TREE_CODE (mref) != MEM_REF)
+ return false;
+
+ /* Consider the access if its type is a derived class. */
+ tree mreftype = TREE_TYPE (mref);
+ if (!RECORD_OR_UNION_TYPE_P (mreftype)
+ || !TYPE_BINFO (mreftype))
+ return false;
+
+ /* Compute the size of the referenced object (it could be dynamically
+ allocated). */
+ access_ref aref; // unused
+ tree refop = TREE_OPERAND (mref, 0);
+ tree refsize = compute_objsize (refop, 1, &aref);
+ if (!refsize || TREE_CODE (refsize) != INTEGER_CST)
+ return false;
+
+ /* Compute the byte offset of the member within its enclosing class. */
+ tree fld = TREE_OPERAND (t, 1);
+ tree fldpos = byte_position (fld);
+ if (TREE_CODE (fldpos) != INTEGER_CST)
+ return false;
+
+ /* Compute the byte offset of the member with the outermost complete
+ object by adding its offset computed above to the MEM_REF offset. */
+ tree refoff = TREE_OPERAND (mref, 1);
+ tree fldoff = int_const_binop (PLUS_EXPR, fldpos, refoff);
+
+ /* Return true if the member offset is less than the size of the complete
+ object. */
+ return tree_int_cst_lt (fldoff, refsize);
+}
+
/* Callback for walk_tree to check a tree for out of bounds array
accesses. The array_bounds_checker class is passed in DATA. */
@@ -919,8 +963,14 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
else if (TREE_CODE (t) == ADDR_EXPR)
{
checker->check_addr_expr (location, t);
- *walk_subtree = FALSE;
+ *walk_subtree = false;
}
+ else if (inbounds_vbase_memaccess_p (t))
+ /* Hack: Skip MEM_REF checks in accesses to a member of a base class
+ at an offset that's within the bounds of the enclosing object.
+ See pr98266 and pr97595. */
+ *walk_subtree = false;
+
/* Propagate the no-warning bit to the outer expression. */
if (warned)
TREE_NO_WARNING (t) = true;
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-15.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-15.C
new file mode 100644
index 0000000..455f3a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-15.C
@@ -0,0 +1,33 @@
+/* PR middle-end/98266 - bogus array subscript is partly outside array
+ bounds on virtual inheritance
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+#if __cplusplus < 201103L
+// This matters for the test case.
+# define noexcept throw ()
+#endif
+
+struct A
+{
+ virtual ~A () noexcept;
+ const char *s;
+};
+
+struct B: virtual A { };
+struct C: virtual A { }; // { dg-bogus "\\\[-Warray-bounds" }
+
+struct D: virtual B, virtual C
+{
+ D (const char*);
+};
+
+void sink (void*);
+void sink (D);
+
+
+// Verify that accesses to the table aren't diagnosed.
+void test_vtbl ()
+{
+ sink (D (""));
+}
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-18.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-18.C
new file mode 100644
index 0000000..53d93cf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-18.C
@@ -0,0 +1,167 @@
+/* PR middle-end/98266 - bogus array subscript is partly outside array
+ bounds on virtual inheritance
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+struct A
+{
+ int ai, aj, aa[2];
+
+ virtual ~A ();
+};
+
+struct B: virtual A { };
+struct C: virtual A { };
+
+void sink (void*);
+
+struct C1: virtual A
+{
+ int c2i, c2j, c2a[2];
+
+ C1 ();
+ ~C1 ()
+ { // { dg-bogus "\\\[-Warray-bounds" }
+ c2i = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ c2j = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ c2a[0] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ c2a[1] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ c2a[2] = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
+ }
+};
+
+struct D1: virtual B, virtual C1
+{
+ D1 ();
+};
+
+void sink (void*);
+
+/* Verify that only out of bounds accesses to members of an ordinary base
+ class are diagnosed. Use direct array accesses. */
+void test_vmem_base_ctor_arryaccess ()
+{
+ D1 d2;
+ sink (&d2);
+}
+
+
+struct C2: virtual A
+{
+ int c3a[2];
+
+ C2 ();
+ ~C2 ()
+ { // { dg-bogus "\\\[-Warray-bounds" }
+ int *p = c3a;
+ *p++ = __LINE__;
+ *p++ = __LINE__;
+ *p++ = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
+ }
+};
+
+struct D2: virtual B, virtual C2
+{
+ D2 ();
+};
+
+/* Verify that only out of bounds accesses to members of an ordinary base
+ class are diagnosed. Use pointer accesses. */
+void test_vmem_base_dtor_ptraccess ()
+{
+ D2 d3;
+ sink (&d3);
+}
+
+
+struct C3: virtual A // { dg-bogus "\\\[-Warray-bounds" }
+{
+ int i, j, a[2];
+
+ C3 ();
+};
+
+struct D3: virtual B, virtual C3
+{
+ D3 ()
+ { // { dg-bogus "\\\[-Warray-bounds" }
+ i = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ j = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ a[0] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ a[1] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ a[2] = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
+ }
+};
+
+/* Verify that only out of bounds accesses to members of an ordinary base
+ class made in the ctor of a derived class are diagnosed. Use direct
+ array accesses. */
+void test_vmem_derived_ctor_arryaccess ()
+{
+ D3 d4;
+ sink (&d4);
+}
+
+
+struct D4: virtual B, virtual C3
+{
+ D4 ()
+ { // { dg-bogus "\\\[-Warray-bounds" }
+ int *p = a;
+ *p++ = __LINE__;
+ *p++ = __LINE__;
+ *p++ = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
+ }
+};
+
+/* Verify that only out of bounds accesses to members of an ordinary base
+ class made in the ctor of a derived class are diagnosed. Use pointer
+ accesses. */
+void test_vmem_derived_ctor_ptraccess ()
+{
+ D4 d5;
+ sink (&d5);
+}
+
+
+struct D5: virtual B, virtual C3 // { dg-bogus "\\\[-Warray-bounds" }
+{
+ ~D5 ()
+ {
+ i = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ j = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ a[0] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ a[1] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
+ a[2] = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
+ }
+};
+
+/* Verify that only out of bounds accesses to members of an ordinary base
+ class made in the dtor of a derived class are diagnosed. Use pointer
+ accesses. */
+void test_vmem_derived_dtor_arryaccess ()
+{
+ D5 d6;
+ sink (&d6);
+}
+
+
+struct D6: virtual B, virtual C3 // { dg-bogus "\\\[-Warray-bounds" }
+{
+ ~D6 ()
+ {
+ int *p = a;
+ *p++ = __LINE__;
+ *p++ = __LINE__;
+ *p++ = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
+ }
+};
+
+/* Verify that only out of bounds accesses to members of an ordinary base
+ class made in the dtor of a derived class are diagnosed. Use pointer
+ accesses. */
+void test_vmem_derived_dtor_ptraccess ()
+{
+ D6 d7;
+ sink (&d7);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-19.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-19.C
new file mode 100644
index 0000000..e5fabe9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-19.C
@@ -0,0 +1,110 @@
+/* PR middle-end/98266 - bogus array subscript is partly outside array
+ bounds on virtual inheritance
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+void* operator new (__SIZE_TYPE__, void *p) { return p; }
+void* operator new[] (__SIZE_TYPE__, void *p) { return p; }
+
+
+struct A
+{
+ virtual ~A ();
+ int ai;
+};
+
+struct B: virtual A { };
+
+
+// Exercise access to base members by ctor of the most derived class.
+
+struct C1: virtual A // { dg-bogus "\\\[-Warray-bounds" }
+{
+ int c1i;
+ C1 ();
+};
+
+struct D1: virtual B, virtual C1
+{
+ D1 () { ai = 0; c1i = 1; };
+};
+
+void sink (void*);
+
+void nowarn_derived_ctor_access_decl ()
+{
+ D1 d1;
+ sink (&d1);
+}
+
+void nowarn_derived_ctor_access_new ()
+{
+ D1 *p = new D1;
+ sink (p);
+}
+
+void nowarn_derived_ctor_access_placement_new ()
+{
+ char a[sizeof (D1)];
+ D1 *p = new (a) D1;
+ sink (p);
+}
+
+void nowarn_derived_ctor_access_new_array ()
+{
+ D1 *p = new D1[2];
+ sink (p);
+}
+
+void nowarn_derived_ctor_access_placement_new_array ()
+{
+ char a[sizeof (D1) * 2];
+ D1 *p = new (a) D1[2];
+ sink (p);
+}
+
+
+// Exercise access to base members by ctor of the second most derived class.
+
+struct C2: virtual A
+{
+ int c2i;
+ ~C2 () { ai = 0; c2i = 1; } // { dg-bogus "\\\[-Warray-bounds"
+};
+
+struct D2: virtual B, virtual C2
+{
+ D2 ();
+};
+
+void nowarn_base_dtor_access_decl ()
+{
+ D2 d2;
+ sink (&d2);
+}
+
+void nowarn_base_dtor_access_new ()
+{
+ D2 *p = new D2;
+ sink (p);
+}
+
+void nowarn_base_dtor_access_placement_new ()
+{
+ char a[sizeof (D2)];
+ D2 *p = new (a) D2;
+ sink (p);
+}
+
+void nowarn_base_dtor_access_new_array ()
+{
+ D2 *p = new D2[2];
+ sink (p);
+}
+
+void nowarn_base_dtor_access_placement_new_array ()
+{
+ char a[sizeof (D2) * 2];
+ D2 *p = new (a) D2[2];
+ sink (p);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-20.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-20.C
new file mode 100644
index 0000000..e142ea1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-20.C
@@ -0,0 +1,68 @@
+/* PR middle-end/98266 - bogus array subscript is partly outside array
+ bounds on virtual inheritance
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+void* operator new (__SIZE_TYPE__, void *p) { return p; }
+void* operator new[] (__SIZE_TYPE__, void *p) { return p; }
+
+
+struct A
+{
+ int ai;
+ virtual ~A ();
+};
+
+struct B: virtual A { };
+
+struct C: virtual A
+{
+ int ci;
+ C ();
+};
+
+struct D1: virtual B, virtual C
+{
+ /* The warning would ideally point to the assignment but instead points
+ to the opening brace. */
+ D1 ()
+ { // { dg-warning "\\\[-Warray-bounds" "brace" }
+ ci = 0; // { dg-warning "\\\[-Warray-bounds" "assign" { xfail *-*-* } }
+ }
+};
+
+void sink (void*);
+
+void warn_derived_ctor_access_new_decl ()
+{
+ char a[sizeof (D1)]; // { dg-message "referencing 'a'" "note" }
+ char *p = a;
+ ++p;
+ D1 *q = new (p) D1;
+ sink (q);
+}
+
+void warn_derived_ctor_access_new_alloc ()
+{
+ char *p = (char*)operator new (sizeof (D1)); // { dg-message "referencing an object of size \\d+ allocated by 'void\\\* operator new\\\(" "note" }
+ ++p;
+ D1 *q = new (p) D1;
+ sink (q);
+}
+
+void warn_derived_ctor_access_new_array_decl ()
+{
+ char b[sizeof (D1) * 2]; // { dg-message "referencing 'b'" "note" }
+ char *p = b;
+ ++p;
+ D1 *q = new (p) D1[2];
+ sink (q);
+}
+
+void warn_derived_ctor_access_new_array_alloc ()
+{
+ char *p = new char[sizeof (D1) * 2]; // { dg-message "referencing an object of size \\d+ allocated by 'void\\\* operator new \\\[]\\\(" "note" }
+ ++p;
+ D1 *q = new (p) D1[2];
+ sink (q);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-21.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-21.C
new file mode 100644
index 0000000..57bb98b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-21.C
@@ -0,0 +1,111 @@
+/* PR middle-end/98266 - bogus array subscript is partly outside array
+ bounds on virtual inheritance
+ Same as Warray-bounds-19.C with nonvirtual inheritance.
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+void* operator new (__SIZE_TYPE__, void *p) { return p; }
+void* operator new[] (__SIZE_TYPE__, void *p) { return p; }
+
+
+struct A
+{
+ virtual ~A ();
+ int ai;
+};
+
+struct B: A { };
+
+
+// Exercise access to base members by ctor of the most derived class.
+
+struct C1: A
+{
+ int c1i;
+ C1 ();
+};
+
+struct D1: B, C1
+{
+ D1 () { B::ai = 0; C1::ai = 1; c1i = 2; };
+};
+
+void sink (void*);
+
+void nowarn_derived_ctor_access_decl ()
+{
+ D1 d1;
+ sink (&d1);
+}
+
+void nowarn_derived_ctor_access_new ()
+{
+ D1 *p = new D1;
+ sink (p);
+}
+
+void nowarn_derived_ctor_access_placement_new ()
+{
+ char a[sizeof (D1)];
+ D1 *p = new (a) D1;
+ sink (p);
+}
+
+void nowarn_derived_ctor_access_new_array ()
+{
+ D1 *p = new D1[2];
+ sink (p);
+}
+
+void nowarn_derived_ctor_access_placement_new_array ()
+{
+ char a[sizeof (D1) * 2];
+ D1 *p = new (a) D1[2];
+ sink (p);
+}
+
+
+// Exercise access to base members by ctor of the second most derived class.
+
+struct C2: A
+{
+ int c2i;
+ ~C2 () { ai = 0; c2i = 1; }
+};
+
+struct D2: B, C2
+{
+ D2 ();
+};
+
+void nowarn_base_dtor_access_decl ()
+{
+ D2 d2;
+ sink (&d2);
+}
+
+void nowarn_base_dtor_access_new ()
+{
+ D2 *p = new D2;
+ sink (p);
+}
+
+void nowarn_base_dtor_access_placement_new ()
+{
+ char a[sizeof (D2)];
+ D2 *p = new (a) D2;
+ sink (p);
+}
+
+void nowarn_base_dtor_access_new_array ()
+{
+ D2 *p = new D2[2];
+ sink (p);
+}
+
+void nowarn_base_dtor_access_placement_new_array ()
+{
+ char a[sizeof (D2) * 2];
+ D2 *p = new (a) D2[2];
+ sink (p);
+}