aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2020-10-09 13:56:53 -0600
committerMartin Sebor <msebor@redhat.com>2020-10-12 09:04:49 -0600
commitde05c19d5fd661ae16dd75a895b49d32d12f5edc (patch)
tree05d9906c75f514094c4320b482f200787a34b9b6 /gcc/builtins.c
parent71dbabccbfb295c87d91719fe72d9d60511c0b44 (diff)
downloadgcc-de05c19d5fd661ae16dd75a895b49d32d12f5edc.zip
gcc-de05c19d5fd661ae16dd75a895b49d32d12f5edc.tar.gz
gcc-de05c19d5fd661ae16dd75a895b49d32d12f5edc.tar.bz2
Correct handling of indices into arrays with elements larger than 1 (PR c++/96511)
Resolves: PR c++/96511 - Incorrect -Wplacement-new on POINTER_PLUS into an array with 4-byte elements PR middle-end/96384 - bogus -Wstringop-overflow= storing into multidimensional array with index in range gcc/ChangeLog: PR c++/96511 PR middle-end/96384 * builtins.c (get_range): Return full range of type when neither value nor its range is available. Fail for ranges inverted due to the signedness of offsets. (compute_objsize): Handle more special array members. Handle POINTER_PLUS_EXPR and VIEW_CONVERT_EXPR that come up in front end code. (access_ref::offset_bounded): Define new member function. * builtins.h (access_ref::eval): New data member. (access_ref::offset_bounded): New member function. (access_ref::offset_zero): New member function. (compute_objsize): Declare a new overload. * gimple-array-bounds.cc (array_bounds_checker::check_array_ref): Use enum special_array_member. * tree.c (component_ref_size): Use special_array_member. * tree.h (special_array_member): Define a new type. (component_ref_size): Change signature. gcc/cp/ChangeLog: PR c++/96511 PR middle-end/96384 * init.c (warn_placement_new_too_small): Call builtin_objsize instead of duplicating what it does. gcc/testsuite/ChangeLog: PR c++/96511 PR middle-end/96384 * g++.dg/init/strlen.C: Add expected warning. * g++.dg/warn/Wplacement-new-size-1.C: Relax warnings. * g++.dg/warn/Wplacement-new-size-2.C: Same. * g++.dg/warn/Wplacement-new-size-6.C: Same. * gcc.dg/Warray-bounds-58.c: Adjust * gcc.dg/Wstringop-overflow-37.c: Same. * g++.dg/warn/Wplacement-new-size-7.C: New test.
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c135
1 files changed, 108 insertions, 27 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 284926f..283c1e6 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -200,7 +200,7 @@ static void expand_builtin_sync_synchronize (void);
access_ref::access_ref (tree bound /* = NULL_TREE */,
bool minaccess /* = false */)
- : ref ()
+: ref (), eval ([](tree x){ return x; }), trail1special (true)
{
/* Set to valid. */
offrng[0] = offrng[1] = 0;
@@ -4370,10 +4370,34 @@ static bool
get_range (tree x, gimple *stmt, signop sgn, offset_int r[2],
range_query *rvals /* = NULL */)
{
+ tree type = TREE_TYPE (x);
+ if (TREE_CODE (x) != INTEGER_CST
+ && TREE_CODE (x) != SSA_NAME)
+ {
+ if (TYPE_UNSIGNED (type))
+ {
+ if (sgn == SIGNED)
+ type = signed_type_for (type);
+ }
+ else if (sgn == UNSIGNED)
+ type = unsigned_type_for (type);
+
+ r[0] = wi::to_offset (TYPE_MIN_VALUE (type));
+ r[1] = wi::to_offset (TYPE_MAX_VALUE (type));
+ return x;
+ }
+
wide_int wr[2];
if (!get_range (x, stmt, wr, rvals))
return false;
+ /* Only convert signed integers or unsigned sizetype to a signed
+ offset and avoid converting large positive values in narrower
+ types to negative offsets. */
+ if (TYPE_UNSIGNED (type)
+ && wr[0].get_precision () < TYPE_PRECISION (sizetype))
+ sgn = UNSIGNED;
+
r[0] = offset_int::from (wr[0], sgn);
r[1] = offset_int::from (wr[1], sgn);
return true;
@@ -4394,9 +4418,11 @@ get_range (tree x, gimple *stmt, signop sgn, offset_int r[2],
to influence code generation or optimization. */
static bool
-compute_objsize (tree ptr, int ostype, access_ref *pref,
- bitmap *visited, range_query *rvals /* = NULL */)
+compute_objsize (tree ptr, int ostype, access_ref *pref, bitmap *visited,
+ range_query *rvals)
{
+ STRIP_NOPS (ptr);
+
const bool addr = TREE_CODE (ptr) == ADDR_EXPR;
if (addr)
ptr = TREE_OPERAND (ptr, 0);
@@ -4408,12 +4434,15 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
if (!addr && POINTER_TYPE_P (TREE_TYPE (ptr)))
return false;
- tree size = decl_init_size (ptr, false);
- if (!size || TREE_CODE (size) != INTEGER_CST)
- return false;
-
pref->ref = ptr;
- pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
+ if (tree size = decl_init_size (ptr, false))
+ if (TREE_CODE (size) == INTEGER_CST)
+ {
+ pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
+ return true;
+ }
+ pref->sizrng[0] = 0;
+ pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
return true;
}
@@ -4421,13 +4450,13 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
if (code == COMPONENT_REF)
{
+ tree ref = TREE_OPERAND (ptr, 0);
tree field = TREE_OPERAND (ptr, 1);
if (ostype == 0)
{
/* For raw memory functions like memcpy bail if the size
of the enclosing object cannot be determined. */
- tree ref = TREE_OPERAND (ptr, 0);
if (!compute_objsize (ref, ostype, pref, visited, rvals)
|| !pref->ref)
return false;
@@ -4449,20 +4478,28 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
return false;
pref->ref = field;
- /* Only return constant sizes for now while callers depend
- on it. INT0LEN is true for interior zero-length arrays. */
- bool int0len = false;
- tree size = component_ref_size (ptr, &int0len);
- if (int0len)
+
+ /* SAM is set for array members that might need special treatment. */
+ special_array_member sam;
+ tree size = component_ref_size (ptr, &sam);
+ if (sam == special_array_member::int_0)
+ pref->sizrng[0] = pref->sizrng[1] = 0;
+ else if (!pref->trail1special && sam == special_array_member::trail_1)
+ pref->sizrng[0] = pref->sizrng[1] = 1;
+ else if (size && TREE_CODE (size) == INTEGER_CST)
+ pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
+ else
{
- pref->sizrng[0] = pref->sizrng[1] = 0;
- return true;
+ /* When the size of the member is unknown it's either a flexible
+ array member or a trailing special array member (either zero
+ length or one-element). Set the size to the maximum minus
+ the constant size of the type. */
+ pref->sizrng[0] = 0;
+ pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
+ if (tree recsize = TYPE_SIZE_UNIT (TREE_TYPE (ref)))
+ if (TREE_CODE (recsize) == INTEGER_CST)
+ pref->sizrng[1] -= wi::to_offset (recsize);
}
-
- if (!size || TREE_CODE (size) != INTEGER_CST)
- return false;
-
- pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
return true;
}
@@ -4492,7 +4529,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
return false;
offset_int orng[2];
- tree off = TREE_OPERAND (ptr, 1);
+ tree off = pref->eval (TREE_OPERAND (ptr, 1));
if (!get_range (off, NULL, SIGNED, orng, rvals))
/* Fail unless the size of the object is zero. */
return pref->sizrng[0] == 0 && pref->sizrng[0] == pref->sizrng[1];
@@ -4522,11 +4559,22 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
if (ostype && TREE_CODE (eltype) == ARRAY_TYPE)
{
- /* Execpt for the permissive raw memory functions which
- use the size of the whole object determined above,
- use the size of the referenced array. */
- pref->sizrng[0] = pref->offrng[0] + orng[0] + sz;
- pref->sizrng[1] = pref->offrng[1] + orng[1] + sz;
+ /* Except for the permissive raw memory functions which use
+ the size of the whole object determined above, use the size
+ of the referenced array. Because the overall offset is from
+ the beginning of the complete array object add this overall
+ offset to the size of array. */
+ offset_int sizrng[2] =
+ {
+ pref->offrng[0] + orng[0] + sz,
+ pref->offrng[1] + orng[1] + sz
+ };
+ if (sizrng[1] < sizrng[0])
+ std::swap (sizrng[0], sizrng[1]);
+ if (sizrng[0] >= 0 && sizrng[0] <= pref->sizrng[0])
+ pref->sizrng[0] = sizrng[0];
+ if (sizrng[1] >= 0 && sizrng[1] <= pref->sizrng[1])
+ pref->sizrng[1] = sizrng[1];
}
}
@@ -4535,6 +4583,28 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
return true;
}
+ else if (code == POINTER_PLUS_EXPR)
+ {
+ tree ref = TREE_OPERAND (ptr, 0);
+ if (!compute_objsize (ref, ostype, pref, visited, rvals))
+ return false;
+
+ offset_int orng[2];
+ tree off = pref->eval (TREE_OPERAND (ptr, 1));
+ if (!get_range (off, NULL, SIGNED, orng, rvals))
+ /* Fail unless the size of the object is zero. */
+ return pref->sizrng[0] == 0 && pref->sizrng[0] == pref->sizrng[1];
+
+ pref->offrng[0] += orng[0];
+ pref->offrng[1] += orng[1];
+
+ return true;
+ }
+ else if (code == VIEW_CONVERT_EXPR)
+ {
+ ptr = TREE_OPERAND (ptr, 0);
+ return compute_objsize (ptr, ostype, pref, visited, rvals);
+ }
if (TREE_CODE (ptr) == SSA_NAME)
{
@@ -12504,3 +12574,14 @@ builtin_with_linkage_p (tree decl)
}
return false;
}
+
+/* Return true if OFFRNG is bounded to a subrange of offset values
+ valid for the largest possible object. */
+
+bool
+access_ref::offset_bounded () const
+{
+ tree min = TYPE_MIN_VALUE (ptrdiff_type_node);
+ tree max = TYPE_MAX_VALUE (ptrdiff_type_node);
+ return wi::to_offset (min) <= offrng[0] && offrng[1] <= wi::to_offset (max);
+}