aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-array-bounds.cc
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/gimple-array-bounds.cc
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/gimple-array-bounds.cc')
-rw-r--r--gcc/gimple-array-bounds.cc52
1 files changed, 51 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;