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.
This commit is contained in:
parent
71dbabccbf
commit
de05c19d5f
13 changed files with 392 additions and 324 deletions
133
gcc/builtins.c
133
gcc/builtins.c
|
@ -200,7 +200,7 @@ static void expand_builtin_sync_synchronize (void);
|
||||||
|
|
||||||
access_ref::access_ref (tree bound /* = NULL_TREE */,
|
access_ref::access_ref (tree bound /* = NULL_TREE */,
|
||||||
bool minaccess /* = false */)
|
bool minaccess /* = false */)
|
||||||
: ref ()
|
: ref (), eval ([](tree x){ return x; }), trail1special (true)
|
||||||
{
|
{
|
||||||
/* Set to valid. */
|
/* Set to valid. */
|
||||||
offrng[0] = offrng[1] = 0;
|
offrng[0] = offrng[1] = 0;
|
||||||
|
@ -4370,10 +4370,34 @@ static bool
|
||||||
get_range (tree x, gimple *stmt, signop sgn, offset_int r[2],
|
get_range (tree x, gimple *stmt, signop sgn, offset_int r[2],
|
||||||
range_query *rvals /* = NULL */)
|
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];
|
wide_int wr[2];
|
||||||
if (!get_range (x, stmt, wr, rvals))
|
if (!get_range (x, stmt, wr, rvals))
|
||||||
return false;
|
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[0] = offset_int::from (wr[0], sgn);
|
||||||
r[1] = offset_int::from (wr[1], sgn);
|
r[1] = offset_int::from (wr[1], sgn);
|
||||||
return true;
|
return true;
|
||||||
|
@ -4394,9 +4418,11 @@ get_range (tree x, gimple *stmt, signop sgn, offset_int r[2],
|
||||||
to influence code generation or optimization. */
|
to influence code generation or optimization. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
compute_objsize (tree ptr, int ostype, access_ref *pref,
|
compute_objsize (tree ptr, int ostype, access_ref *pref, bitmap *visited,
|
||||||
bitmap *visited, range_query *rvals /* = NULL */)
|
range_query *rvals)
|
||||||
{
|
{
|
||||||
|
STRIP_NOPS (ptr);
|
||||||
|
|
||||||
const bool addr = TREE_CODE (ptr) == ADDR_EXPR;
|
const bool addr = TREE_CODE (ptr) == ADDR_EXPR;
|
||||||
if (addr)
|
if (addr)
|
||||||
ptr = TREE_OPERAND (ptr, 0);
|
ptr = TREE_OPERAND (ptr, 0);
|
||||||
|
@ -4408,26 +4434,29 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
|
||||||
if (!addr && POINTER_TYPE_P (TREE_TYPE (ptr)))
|
if (!addr && POINTER_TYPE_P (TREE_TYPE (ptr)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
tree size = decl_init_size (ptr, false);
|
|
||||||
if (!size || TREE_CODE (size) != INTEGER_CST)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pref->ref = ptr;
|
pref->ref = ptr;
|
||||||
|
if (tree size = decl_init_size (ptr, false))
|
||||||
|
if (TREE_CODE (size) == INTEGER_CST)
|
||||||
|
{
|
||||||
pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
|
pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
pref->sizrng[0] = 0;
|
||||||
|
pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const tree_code code = TREE_CODE (ptr);
|
const tree_code code = TREE_CODE (ptr);
|
||||||
|
|
||||||
if (code == COMPONENT_REF)
|
if (code == COMPONENT_REF)
|
||||||
{
|
{
|
||||||
|
tree ref = TREE_OPERAND (ptr, 0);
|
||||||
tree field = TREE_OPERAND (ptr, 1);
|
tree field = TREE_OPERAND (ptr, 1);
|
||||||
|
|
||||||
if (ostype == 0)
|
if (ostype == 0)
|
||||||
{
|
{
|
||||||
/* For raw memory functions like memcpy bail if the size
|
/* For raw memory functions like memcpy bail if the size
|
||||||
of the enclosing object cannot be determined. */
|
of the enclosing object cannot be determined. */
|
||||||
tree ref = TREE_OPERAND (ptr, 0);
|
|
||||||
if (!compute_objsize (ref, ostype, pref, visited, rvals)
|
if (!compute_objsize (ref, ostype, pref, visited, rvals)
|
||||||
|| !pref->ref)
|
|| !pref->ref)
|
||||||
return false;
|
return false;
|
||||||
|
@ -4449,20 +4478,28 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pref->ref = field;
|
pref->ref = field;
|
||||||
/* Only return constant sizes for now while callers depend
|
|
||||||
on it. INT0LEN is true for interior zero-length arrays. */
|
/* SAM is set for array members that might need special treatment. */
|
||||||
bool int0len = false;
|
special_array_member sam;
|
||||||
tree size = component_ref_size (ptr, &int0len);
|
tree size = component_ref_size (ptr, &sam);
|
||||||
if (int0len)
|
if (sam == special_array_member::int_0)
|
||||||
{
|
|
||||||
pref->sizrng[0] = pref->sizrng[1] = 0;
|
pref->sizrng[0] = pref->sizrng[1] = 0;
|
||||||
return true;
|
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)
|
||||||
if (!size || TREE_CODE (size) != INTEGER_CST)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
|
pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4492,7 +4529,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
offset_int orng[2];
|
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))
|
if (!get_range (off, NULL, SIGNED, orng, rvals))
|
||||||
/* Fail unless the size of the object is zero. */
|
/* Fail unless the size of the object is zero. */
|
||||||
return pref->sizrng[0] == 0 && pref->sizrng[0] == pref->sizrng[1];
|
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)
|
if (ostype && TREE_CODE (eltype) == ARRAY_TYPE)
|
||||||
{
|
{
|
||||||
/* Execpt for the permissive raw memory functions which
|
/* Except for the permissive raw memory functions which use
|
||||||
use the size of the whole object determined above,
|
the size of the whole object determined above, use the size
|
||||||
use the size of the referenced array. */
|
of the referenced array. Because the overall offset is from
|
||||||
pref->sizrng[0] = pref->offrng[0] + orng[0] + sz;
|
the beginning of the complete array object add this overall
|
||||||
pref->sizrng[1] = pref->offrng[1] + orng[1] + sz;
|
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;
|
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)
|
if (TREE_CODE (ptr) == SSA_NAME)
|
||||||
{
|
{
|
||||||
|
@ -12504,3 +12574,14 @@ builtin_with_linkage_p (tree decl)
|
||||||
}
|
}
|
||||||
return false;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -173,6 +173,22 @@ struct access_ref
|
||||||
For string functions the size of the actual access is
|
For string functions the size of the actual access is
|
||||||
further constrained by the length of the string. */
|
further constrained by the length of the string. */
|
||||||
offset_int bndrng[2];
|
offset_int bndrng[2];
|
||||||
|
|
||||||
|
/* Return true if OFFRNG is the constant zero. */
|
||||||
|
bool offset_zero () const
|
||||||
|
{
|
||||||
|
return offrng[0] == 0 && offrng[1] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if OFFRNG is bounded to a subrange of possible offset
|
||||||
|
values. */
|
||||||
|
bool offset_bounded () const;
|
||||||
|
|
||||||
|
/* Used to fold integer expressions when called from front ends. */
|
||||||
|
tree (*eval)(tree);
|
||||||
|
/* Set if trailing one-element arrays should be treated as flexible
|
||||||
|
array members. */
|
||||||
|
bool trail1special;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Describes a pair of references used in an access by built-in
|
/* Describes a pair of references used in an access by built-in
|
||||||
|
|
296
gcc/cp/init.c
296
gcc/cp/init.c
|
@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "attribs.h"
|
#include "attribs.h"
|
||||||
#include "asan.h"
|
#include "asan.h"
|
||||||
#include "stor-layout.h"
|
#include "stor-layout.h"
|
||||||
|
#include "builtins.h"
|
||||||
|
|
||||||
static bool begin_init_stmts (tree *, tree *);
|
static bool begin_init_stmts (tree *, tree *);
|
||||||
static tree finish_init_stmts (bool, tree, tree);
|
static tree finish_init_stmts (bool, tree, tree);
|
||||||
|
@ -2564,27 +2565,6 @@ throw_bad_array_new_length (void)
|
||||||
return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
|
return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt to find the initializer for flexible array field T in the
|
|
||||||
initializer INIT, when non-null. Returns the initializer when
|
|
||||||
successful and NULL otherwise. */
|
|
||||||
static tree
|
|
||||||
find_flexarray_init (tree t, tree init)
|
|
||||||
{
|
|
||||||
if (!init || init == error_mark_node)
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
unsigned HOST_WIDE_INT idx;
|
|
||||||
tree field, elt;
|
|
||||||
|
|
||||||
/* Iterate over all top-level initializer elements. */
|
|
||||||
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, elt)
|
|
||||||
/* If the member T is found, return it. */
|
|
||||||
if (field == t)
|
|
||||||
return elt;
|
|
||||||
|
|
||||||
return NULL_TREE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Attempt to verify that the argument, OPER, of a placement new expression
|
/* Attempt to verify that the argument, OPER, of a placement new expression
|
||||||
refers to an object sufficiently large for an object of TYPE or an array
|
refers to an object sufficiently large for an object of TYPE or an array
|
||||||
of NELTS of such objects when NELTS is non-null, and issue a warning when
|
of NELTS of such objects when NELTS is non-null, and issue a warning when
|
||||||
|
@ -2601,17 +2581,6 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
|
||||||
{
|
{
|
||||||
location_t loc = cp_expr_loc_or_input_loc (oper);
|
location_t loc = cp_expr_loc_or_input_loc (oper);
|
||||||
|
|
||||||
/* The number of bytes to add to or subtract from the size of the provided
|
|
||||||
buffer based on an offset into an array or an array element reference.
|
|
||||||
Although intermediate results may be negative (as in a[3] - 2) a valid
|
|
||||||
final result cannot be. */
|
|
||||||
offset_int adjust = 0;
|
|
||||||
/* True when the size of the entire destination object should be used
|
|
||||||
to compute the possibly optimistic estimate of the available space. */
|
|
||||||
bool use_obj_size = false;
|
|
||||||
/* True when the reference to the destination buffer is an ADDR_EXPR. */
|
|
||||||
bool addr_expr = false;
|
|
||||||
|
|
||||||
STRIP_NOPS (oper);
|
STRIP_NOPS (oper);
|
||||||
|
|
||||||
/* Using a function argument or a (non-array) variable as an argument
|
/* Using a function argument or a (non-array) variable as an argument
|
||||||
|
@ -2625,181 +2594,16 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
|
||||||
/* Evaluate any constant expressions. */
|
/* Evaluate any constant expressions. */
|
||||||
size = fold_non_dependent_expr (size);
|
size = fold_non_dependent_expr (size);
|
||||||
|
|
||||||
/* Handle the common case of array + offset expression when the offset
|
access_ref ref;
|
||||||
is a constant. */
|
ref.eval = [](tree x){ return fold_non_dependent_expr (x); };
|
||||||
if (TREE_CODE (oper) == POINTER_PLUS_EXPR)
|
ref.trail1special = warn_placement_new < 2;
|
||||||
{
|
tree objsize = compute_objsize (oper, 1, &ref);
|
||||||
/* If the offset is compile-time constant, use it to compute a more
|
if (!objsize)
|
||||||
accurate estimate of the size of the buffer. Since the operand
|
|
||||||
of POINTER_PLUS_EXPR is represented as an unsigned type, convert
|
|
||||||
it to signed first.
|
|
||||||
Otherwise, use the size of the entire array as an optimistic
|
|
||||||
estimate (this may lead to false negatives). */
|
|
||||||
tree adj = TREE_OPERAND (oper, 1);
|
|
||||||
adj = fold_for_warn (adj);
|
|
||||||
if (CONSTANT_CLASS_P (adj))
|
|
||||||
adjust += wi::to_offset (convert (ssizetype, adj));
|
|
||||||
else
|
|
||||||
use_obj_size = true;
|
|
||||||
|
|
||||||
oper = TREE_OPERAND (oper, 0);
|
|
||||||
|
|
||||||
STRIP_NOPS (oper);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TREE_CODE (oper) == TARGET_EXPR)
|
|
||||||
oper = TREE_OPERAND (oper, 1);
|
|
||||||
else if (TREE_CODE (oper) == ADDR_EXPR)
|
|
||||||
{
|
|
||||||
addr_expr = true;
|
|
||||||
oper = TREE_OPERAND (oper, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
STRIP_NOPS (oper);
|
|
||||||
|
|
||||||
if (TREE_CODE (oper) == ARRAY_REF
|
|
||||||
&& (addr_expr || TREE_CODE (TREE_TYPE (oper)) == ARRAY_TYPE))
|
|
||||||
{
|
|
||||||
/* Similar to the offset computed above, see if the array index
|
|
||||||
is a compile-time constant. If so, and unless the offset was
|
|
||||||
not a compile-time constant, use the index to determine the
|
|
||||||
size of the buffer. Otherwise, use the entire array as
|
|
||||||
an optimistic estimate of the size. */
|
|
||||||
const_tree adj = fold_non_dependent_expr (TREE_OPERAND (oper, 1));
|
|
||||||
if (!use_obj_size && CONSTANT_CLASS_P (adj))
|
|
||||||
adjust += wi::to_offset (adj);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
use_obj_size = true;
|
|
||||||
adjust = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
oper = TREE_OPERAND (oper, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Refers to the declared object that constains the subobject referenced
|
|
||||||
by OPER. When the object is initialized, makes it possible to determine
|
|
||||||
the actual size of a flexible array member used as the buffer passed
|
|
||||||
as OPER to placement new. */
|
|
||||||
tree var_decl = NULL_TREE;
|
|
||||||
/* True when operand is a COMPONENT_REF, to distinguish flexible array
|
|
||||||
members from arrays of unspecified size. */
|
|
||||||
bool compref = TREE_CODE (oper) == COMPONENT_REF;
|
|
||||||
|
|
||||||
/* For COMPONENT_REF (i.e., a struct member) the size of the entire
|
|
||||||
enclosing struct. Used to validate the adjustment (offset) into
|
|
||||||
an array at the end of a struct. */
|
|
||||||
offset_int compsize = 0;
|
|
||||||
|
|
||||||
/* Descend into a struct or union to find the member whose address
|
|
||||||
is being used as the argument. */
|
|
||||||
if (TREE_CODE (oper) == COMPONENT_REF)
|
|
||||||
{
|
|
||||||
tree comptype = TREE_TYPE (TREE_OPERAND (oper, 0));
|
|
||||||
compsize = wi::to_offset (TYPE_SIZE_UNIT (comptype));
|
|
||||||
|
|
||||||
tree op0 = oper;
|
|
||||||
while (TREE_CODE (op0 = TREE_OPERAND (op0, 0)) == COMPONENT_REF);
|
|
||||||
STRIP_ANY_LOCATION_WRAPPER (op0);
|
|
||||||
if (VAR_P (op0))
|
|
||||||
var_decl = op0;
|
|
||||||
oper = TREE_OPERAND (oper, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
STRIP_ANY_LOCATION_WRAPPER (oper);
|
|
||||||
tree opertype = TREE_TYPE (oper);
|
|
||||||
if ((addr_expr || !INDIRECT_TYPE_P (opertype))
|
|
||||||
&& (VAR_P (oper)
|
|
||||||
|| TREE_CODE (oper) == FIELD_DECL
|
|
||||||
|| TREE_CODE (oper) == PARM_DECL))
|
|
||||||
{
|
|
||||||
/* A possibly optimistic estimate of the number of bytes available
|
|
||||||
in the destination buffer. */
|
|
||||||
offset_int bytes_avail = 0;
|
|
||||||
/* True when the estimate above is in fact the exact size
|
|
||||||
of the destination buffer rather than an estimate. */
|
|
||||||
bool exact_size = true;
|
|
||||||
|
|
||||||
/* Treat members of unions and members of structs uniformly, even
|
|
||||||
though the size of a member of a union may be viewed as extending
|
|
||||||
to the end of the union itself (it is by __builtin_object_size). */
|
|
||||||
if ((VAR_P (oper) || use_obj_size)
|
|
||||||
&& DECL_SIZE_UNIT (oper)
|
|
||||||
&& tree_fits_uhwi_p (DECL_SIZE_UNIT (oper)))
|
|
||||||
{
|
|
||||||
/* Use the size of the entire array object when the expression
|
|
||||||
refers to a variable or its size depends on an expression
|
|
||||||
that's not a compile-time constant. */
|
|
||||||
bytes_avail = wi::to_offset (DECL_SIZE_UNIT (oper));
|
|
||||||
exact_size = !use_obj_size;
|
|
||||||
}
|
|
||||||
else if (tree opersize = TYPE_SIZE_UNIT (opertype))
|
|
||||||
{
|
|
||||||
/* Use the size of the type of the destination buffer object
|
|
||||||
as the optimistic estimate of the available space in it.
|
|
||||||
Use the maximum possible size for zero-size arrays and
|
|
||||||
flexible array members (except of initialized objects
|
|
||||||
thereof). */
|
|
||||||
if (TREE_CODE (opersize) == INTEGER_CST)
|
|
||||||
bytes_avail = wi::to_offset (opersize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes_avail == 0)
|
|
||||||
{
|
|
||||||
if (var_decl)
|
|
||||||
{
|
|
||||||
/* Constructing into a buffer provided by the flexible array
|
|
||||||
member of a declared object (which is permitted as a G++
|
|
||||||
extension). If the array member has been initialized,
|
|
||||||
determine its size from the initializer. Otherwise,
|
|
||||||
the array size is zero. */
|
|
||||||
if (tree init = find_flexarray_init (oper,
|
|
||||||
DECL_INITIAL (var_decl)))
|
|
||||||
bytes_avail = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (init)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
bytes_avail = (wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node))
|
|
||||||
- compsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
tree_code oper_code = TREE_CODE (opertype);
|
|
||||||
|
|
||||||
if (compref && oper_code == ARRAY_TYPE)
|
|
||||||
{
|
|
||||||
tree nelts = array_type_nelts_top (opertype);
|
|
||||||
tree nelts_cst = maybe_constant_value (nelts);
|
|
||||||
if (TREE_CODE (nelts_cst) == INTEGER_CST
|
|
||||||
&& integer_onep (nelts_cst)
|
|
||||||
&& !var_decl
|
|
||||||
&& warn_placement_new < 2)
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* Reduce the size of the buffer by the adjustment computed above
|
offset_int bytes_avail = wi::to_offset (objsize);
|
||||||
from the offset and/or the index into the array. */
|
|
||||||
if (bytes_avail < adjust || adjust < 0)
|
|
||||||
bytes_avail = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tree elttype = (TREE_CODE (opertype) == ARRAY_TYPE
|
|
||||||
? TREE_TYPE (opertype) : opertype);
|
|
||||||
if (tree eltsize = TYPE_SIZE_UNIT (elttype))
|
|
||||||
{
|
|
||||||
bytes_avail -= adjust * wi::to_offset (eltsize);
|
|
||||||
if (bytes_avail < 0)
|
|
||||||
bytes_avail = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The minimum amount of space needed for the allocation. This
|
|
||||||
is an optimistic estimate that makes it possible to detect
|
|
||||||
placement new invocation for some undersize buffers but not
|
|
||||||
others. */
|
|
||||||
offset_int bytes_need;
|
offset_int bytes_need;
|
||||||
|
|
||||||
if (nelts)
|
|
||||||
nelts = fold_for_warn (nelts);
|
|
||||||
|
|
||||||
if (CONSTANT_CLASS_P (size))
|
if (CONSTANT_CLASS_P (size))
|
||||||
bytes_need = wi::to_offset (size);
|
bytes_need = wi::to_offset (size);
|
||||||
else if (nelts && CONSTANT_CLASS_P (nelts))
|
else if (nelts && CONSTANT_CLASS_P (nelts))
|
||||||
|
@ -2813,43 +2617,73 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_avail < bytes_need)
|
if (bytes_avail >= bytes_need)
|
||||||
{
|
return;
|
||||||
|
|
||||||
|
/* True when the size to mention in the warning is exact as opposed
|
||||||
|
to "at least N". */
|
||||||
|
const bool exact_size = (ref.offrng[0] == ref.offrng[1]
|
||||||
|
|| ref.sizrng[1] - ref.offrng[0] == 0);
|
||||||
|
|
||||||
|
tree opertype = ref.ref ? TREE_TYPE (ref.ref) : TREE_TYPE (oper);
|
||||||
|
bool warned = false;
|
||||||
|
if (nelts)
|
||||||
|
nelts = fold_for_warn (nelts);
|
||||||
if (nelts)
|
if (nelts)
|
||||||
if (CONSTANT_CLASS_P (nelts))
|
if (CONSTANT_CLASS_P (nelts))
|
||||||
warning_at (loc, OPT_Wplacement_new_,
|
warned = warning_at (loc, OPT_Wplacement_new_,
|
||||||
exact_size ?
|
(exact_size
|
||||||
"placement new constructing an object of type "
|
? G_("placement new constructing an object "
|
||||||
"%<%T [%wu]%> and size %qwu in a region of type %qT "
|
"of type %<%T [%wu]%> and size %qwu "
|
||||||
"and size %qwi"
|
"in a region of type %qT and size %qwi")
|
||||||
: "placement new constructing an object of type "
|
: G_("placement new constructing an object "
|
||||||
"%<%T [%wu]%> and size %qwu in a region of type %qT "
|
"of type %<%T [%wu]%> and size %qwu "
|
||||||
"and size at most %qwu",
|
"in a region of type %qT and size "
|
||||||
type, tree_to_uhwi (nelts), bytes_need.to_uhwi (),
|
"at most %qwu")),
|
||||||
|
type, tree_to_uhwi (nelts),
|
||||||
|
bytes_need.to_uhwi (),
|
||||||
opertype, bytes_avail.to_uhwi ());
|
opertype, bytes_avail.to_uhwi ());
|
||||||
else
|
else
|
||||||
warning_at (loc, OPT_Wplacement_new_,
|
warned = warning_at (loc, OPT_Wplacement_new_,
|
||||||
exact_size ?
|
(exact_size
|
||||||
"placement new constructing an array of objects "
|
? G_("placement new constructing an array "
|
||||||
"of type %qT and size %qwu in a region of type %qT "
|
"of objects of type %qT and size %qwu "
|
||||||
"and size %qwi"
|
"in a region of type %qT and size %qwi")
|
||||||
: "placement new constructing an array of objects "
|
: G_("placement new constructing an array "
|
||||||
"of type %qT and size %qwu in a region of type %qT "
|
"of objects of type %qT and size %qwu "
|
||||||
"and size at most %qwu",
|
"in a region of type %qT and size "
|
||||||
|
"at most %qwu")),
|
||||||
type, bytes_need.to_uhwi (), opertype,
|
type, bytes_need.to_uhwi (), opertype,
|
||||||
bytes_avail.to_uhwi ());
|
bytes_avail.to_uhwi ());
|
||||||
else
|
else
|
||||||
warning_at (loc, OPT_Wplacement_new_,
|
warned = warning_at (loc, OPT_Wplacement_new_,
|
||||||
exact_size ?
|
(exact_size
|
||||||
"placement new constructing an object of type %qT "
|
? G_("placement new constructing an object "
|
||||||
"and size %qwu in a region of type %qT and size %qwi"
|
"of type %qT and size %qwu in a region "
|
||||||
: "placement new constructing an object of type %qT "
|
"of type %qT and size %qwi")
|
||||||
"and size %qwu in a region of type %qT and size "
|
: G_("placement new constructing an object "
|
||||||
"at most %qwu",
|
"of type %qT "
|
||||||
|
"and size %qwu in a region of type %qT "
|
||||||
|
"and size at most %qwu")),
|
||||||
type, bytes_need.to_uhwi (), opertype,
|
type, bytes_need.to_uhwi (), opertype,
|
||||||
bytes_avail.to_uhwi ());
|
bytes_avail.to_uhwi ());
|
||||||
}
|
|
||||||
}
|
if (!warned || !ref.ref)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ref.offrng[0] == 0 || !ref.offset_bounded ())
|
||||||
|
/* Avoid mentioning the offset when its lower bound is zero
|
||||||
|
or when it's impossibly large. */
|
||||||
|
inform (DECL_SOURCE_LOCATION (ref.ref),
|
||||||
|
"%qD declared here", ref.ref);
|
||||||
|
else if (ref.offrng[0] == ref.offrng[1])
|
||||||
|
inform (DECL_SOURCE_LOCATION (ref.ref),
|
||||||
|
"at offset %wi from %qD declared here",
|
||||||
|
ref.offrng[0].to_shwi (), ref.ref);
|
||||||
|
else
|
||||||
|
inform (DECL_SOURCE_LOCATION (ref.ref),
|
||||||
|
"at offset [%wi, %wi] from %qD declared here",
|
||||||
|
ref.offrng[0].to_shwi (), ref.offrng[1].to_shwi (), ref.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* True if alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__. */
|
/* True if alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__. */
|
||||||
|
|
|
@ -188,7 +188,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
|
||||||
tree decl = NULL_TREE;
|
tree decl = NULL_TREE;
|
||||||
|
|
||||||
/* Set for accesses to interior zero-length arrays. */
|
/* Set for accesses to interior zero-length arrays. */
|
||||||
bool interior_zero_len = false;
|
special_array_member sam{ };
|
||||||
|
|
||||||
tree up_bound_p1;
|
tree up_bound_p1;
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
|
||||||
{
|
{
|
||||||
/* Try to determine the size of the trailing array from
|
/* Try to determine the size of the trailing array from
|
||||||
its initializer (if it has one). */
|
its initializer (if it has one). */
|
||||||
if (tree refsize = component_ref_size (arg, &interior_zero_len))
|
if (tree refsize = component_ref_size (arg, &sam))
|
||||||
if (TREE_CODE (refsize) == INTEGER_CST)
|
if (TREE_CODE (refsize) == INTEGER_CST)
|
||||||
maxbound = refsize;
|
maxbound = refsize;
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
|
||||||
"array subscript %E is below array bounds of %qT",
|
"array subscript %E is below array bounds of %qT",
|
||||||
low_sub, artype);
|
low_sub, artype);
|
||||||
|
|
||||||
if (!warned && interior_zero_len)
|
if (!warned && sam == special_array_member::int_0)
|
||||||
warned = warning_at (location, OPT_Wzero_length_bounds,
|
warned = warning_at (location, OPT_Wzero_length_bounds,
|
||||||
(TREE_CODE (low_sub) == INTEGER_CST
|
(TREE_CODE (low_sub) == INTEGER_CST
|
||||||
? G_("array subscript %E is outside the bounds "
|
? G_("array subscript %E is outside the bounds "
|
||||||
|
|
|
@ -29,7 +29,7 @@ test_dynamic_type (S *p)
|
||||||
// distinguish invalid cases from ones like it that might be valid.
|
// distinguish invalid cases from ones like it that might be valid.
|
||||||
// If/when GIMPLE changes to make this possible this test can be
|
// If/when GIMPLE changes to make this possible this test can be
|
||||||
// removed.
|
// removed.
|
||||||
char *q = new (p->a) char [16];
|
char *q = new (p->a) char [16]; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
|
||||||
init (q);
|
init (q);
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,9 @@ struct BA2 { int i; A2 a2; };
|
||||||
void fBx (BAx *pbx, BAx &rbx)
|
void fBx (BAx *pbx, BAx &rbx)
|
||||||
{
|
{
|
||||||
BAx bax;
|
BAx bax;
|
||||||
new (bax.ax.a) char; // { dg-warning "placement" }
|
// The uninitialized flexible array takes up the bytes of padding.
|
||||||
new (bax.ax.a) Int16; // { dg-warning "placement" }
|
new (bax.ax.a) char;
|
||||||
|
new (bax.ax.a) Int16;
|
||||||
new (bax.ax.a) Int32; // { dg-warning "placement" }
|
new (bax.ax.a) Int32; // { dg-warning "placement" }
|
||||||
|
|
||||||
new (pbx->ax.a) char;
|
new (pbx->ax.a) char;
|
||||||
|
@ -84,9 +85,12 @@ void fBx1 ()
|
||||||
{
|
{
|
||||||
static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } };
|
static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } };
|
||||||
|
|
||||||
new (bax1.ax.a) char; // { dg-warning "placement" }
|
// The empty flexible array takes up the bytes of padding.
|
||||||
new (bax1.ax.a) char[2]; // { dg-warning "placement" }
|
new (bax1.ax.a) char;
|
||||||
new (bax1.ax.a) Int16; // { dg-warning "placement" }
|
new (bax1.ax.a) char[2];
|
||||||
|
new (bax1.ax.a) Int16;
|
||||||
|
new (bax1.ax.a) char[3];
|
||||||
|
new (bax1.ax.a) char[4]; // { dg-warning "placement" }
|
||||||
new (bax1.ax.a) Int32; // { dg-warning "placement" }
|
new (bax1.ax.a) Int32; // { dg-warning "placement" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,9 +124,13 @@ struct BA2 { int i; A2 a2; };
|
||||||
void fBx (BAx *pbx, BAx &rbx)
|
void fBx (BAx *pbx, BAx &rbx)
|
||||||
{
|
{
|
||||||
BAx bax;
|
BAx bax;
|
||||||
new (bax.ax.a) char; // { dg-warning "placement" }
|
// The uninitialized flexible array takes up the bytes of padding.
|
||||||
new (bax.ax.a) Int16; // { dg-warning "placement" }
|
new (bax.ax.a) char;
|
||||||
|
new (bax.ax.a) Int16;
|
||||||
|
new (bax.ax.a) char[3];
|
||||||
new (bax.ax.a) Int32; // { dg-warning "placement" }
|
new (bax.ax.a) Int32; // { dg-warning "placement" }
|
||||||
|
new (bax.ax.a) char[4]; // { dg-warning "placement" }
|
||||||
|
new (bax.ax.a) char[5]; // { dg-warning "placement" }
|
||||||
|
|
||||||
new (pbx->ax.a) char;
|
new (pbx->ax.a) char;
|
||||||
new (rbx.ax.a) char;
|
new (rbx.ax.a) char;
|
||||||
|
@ -142,10 +146,14 @@ void fBx1 ()
|
||||||
{
|
{
|
||||||
static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } };
|
static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } };
|
||||||
|
|
||||||
new (bax1.ax.a) char; // { dg-warning "placement" }
|
// The empty flexible array takes up the bytes of padding.
|
||||||
new (bax1.ax.a) char[2]; // { dg-warning "placement" }
|
new (bax1.ax.a) char;
|
||||||
new (bax1.ax.a) Int16; // { dg-warning "placement" }
|
new (bax1.ax.a) char[2];
|
||||||
|
new (bax1.ax.a) Int16;
|
||||||
|
new (bax1.ax.a) char[3];
|
||||||
new (bax1.ax.a) Int32; // { dg-warning "placement" }
|
new (bax1.ax.a) Int32; // { dg-warning "placement" }
|
||||||
|
new (bax1.ax.a) char[4]; // { dg-warning "placement" }
|
||||||
|
new (bax1.ax.a) char[5]; // { dg-warning "placement" }
|
||||||
}
|
}
|
||||||
|
|
||||||
void fB0 (BA0 *pb0, BA0 &rb0)
|
void fB0 (BA0 *pb0, BA0 &rb0)
|
||||||
|
|
|
@ -17,9 +17,10 @@ void fBx1 ()
|
||||||
{
|
{
|
||||||
static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } }; // { dg-error "initialization of flexible array member in a nested context" }
|
static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } }; // { dg-error "initialization of flexible array member in a nested context" }
|
||||||
|
|
||||||
new (bax1.ax.a) char; // { dg-warning "placement" }
|
// The first three bytes of the flexible array member live in the padding.
|
||||||
new (bax1.ax.a) char[2]; // { dg-warning "placement" }
|
new (bax1.ax.a) char;
|
||||||
new (bax1.ax.a) Int16; // { dg-warning "placement" }
|
new (bax1.ax.a) char[2];
|
||||||
|
new (bax1.ax.a) Int16;
|
||||||
new (bax1.ax.a) Int32; // { dg-warning "placement" }
|
new (bax1.ax.a) Int32; // { dg-warning "placement" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +28,11 @@ void fBx2 ()
|
||||||
{
|
{
|
||||||
static BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } }; // { dg-error "initialization of flexible array member in a nested context" }
|
static BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } }; // { dg-error "initialization of flexible array member in a nested context" }
|
||||||
|
|
||||||
new (bax2.ax.a) char; // { dg-warning "placement" }
|
// The first three bytes of the flexible array member live in the padding.
|
||||||
new (bax2.ax.a) char[2]; // { dg-warning "placement" }
|
new (bax2.ax.a) char;
|
||||||
new (bax2.ax.a) char[3]; // { dg-warning "placement" }
|
new (bax2.ax.a) char[2];
|
||||||
new (bax2.ax.a) Int16; // { dg-warning "placement" }
|
new (bax2.ax.a) char[3];
|
||||||
|
new (bax2.ax.a) Int16;
|
||||||
new (bax2.ax.a) char[4]; // { dg-warning "placement" }
|
new (bax2.ax.a) char[4]; // { dg-warning "placement" }
|
||||||
new (bax2.ax.a) Int32; // { dg-warning "placement" }
|
new (bax2.ax.a) Int32; // { dg-warning "placement" }
|
||||||
}
|
}
|
||||||
|
@ -39,10 +41,11 @@ void fBx3 ()
|
||||||
{
|
{
|
||||||
static BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } }; // { dg-error "initialization of flexible array member in a nested context" }
|
static BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } }; // { dg-error "initialization of flexible array member in a nested context" }
|
||||||
|
|
||||||
new (bax2.ax.a) char; // { dg-warning "placement" }
|
// The first three bytes of the flexible array member live in the padding.
|
||||||
new (bax2.ax.a) char[2]; // { dg-warning "placement" }
|
new (bax2.ax.a) char;
|
||||||
new (bax2.ax.a) Int16; // { dg-warning "placement" }
|
new (bax2.ax.a) char[2];
|
||||||
new (bax2.ax.a) char[3]; // { dg-warning "placement" }
|
new (bax2.ax.a) Int16;
|
||||||
|
new (bax2.ax.a) char[3];
|
||||||
new (bax2.ax.a) char[4]; // { dg-warning "placement" }
|
new (bax2.ax.a) char[4]; // { dg-warning "placement" }
|
||||||
new (bax2.ax.a) Int32; // { dg-warning "placement" }
|
new (bax2.ax.a) Int32; // { dg-warning "placement" }
|
||||||
}
|
}
|
||||||
|
|
82
gcc/testsuite/g++.dg/warn/Wplacement-new-size-7.C
Normal file
82
gcc/testsuite/g++.dg/warn/Wplacement-new-size-7.C
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/* PR c++/96511 - Incorrect -Wplacement-new on POINTER_PLUS into an array
|
||||||
|
with 4-byte elements
|
||||||
|
{ dg-do compile }
|
||||||
|
{ dg-options "-Wall" } */
|
||||||
|
|
||||||
|
typedef __INT16_TYPE__ int16_t;
|
||||||
|
typedef __INT32_TYPE__ int32_t;
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
|
||||||
|
void* operator new (size_t, void *p) { return p; }
|
||||||
|
|
||||||
|
void test_a1_int16 ()
|
||||||
|
{
|
||||||
|
int16_t a3[3]; // { dg-message "declared here" }
|
||||||
|
|
||||||
|
new (a3) int16_t;
|
||||||
|
new (a3 + 1) int16_t;
|
||||||
|
new (a3 + 2) int16_t; // { dg-bogus "\\\[-Wplacement-new" }
|
||||||
|
new (&a3[1]) int16_t;
|
||||||
|
new (&a3[0] + 1) int16_t;
|
||||||
|
new (&a3[0] + 2) int16_t; // { dg-bogus "\\\[-Wplacement-new" }
|
||||||
|
new (&a3[0] + 3) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_a1_int32 ()
|
||||||
|
{
|
||||||
|
int16_t a3[3];
|
||||||
|
|
||||||
|
new (a3 + 1) int32_t; // { dg-bogus "\\\[-Wplacement-new" }
|
||||||
|
new (&a3[1]) int32_t;
|
||||||
|
new (&a3[0] + 1) int32_t; // { dg-bogus "\\\[-Wplacement-new" }
|
||||||
|
new (&a3[0] + 2) int32_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void test_a2 ()
|
||||||
|
{
|
||||||
|
int16_t a23[2][3];
|
||||||
|
|
||||||
|
new (a23 + 1) int16_t; // { dg-bogus "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[1]) int16_t;
|
||||||
|
new (&a23[2]) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
|
||||||
|
new (&a23[0][0] + 1) int16_t;
|
||||||
|
new (&a23[0][0] + 2) int16_t;
|
||||||
|
// Deriving a pointer to the next array from one to an element of
|
||||||
|
// the prior array isn't valid even if the resulting pointer points
|
||||||
|
// to an element of the larger array. Verify it's diagnosed.
|
||||||
|
new (&a23[0][0] + 3) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][0] + 4) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][0] + 5) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][0] + 6) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
|
||||||
|
new (&a23[0][1] + 1) int16_t;
|
||||||
|
new (&a23[0][1] + 2) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][1] + 3) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][1] + 4) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][1] + 5) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][1] + 6) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
|
||||||
|
new (&a23[0][2] + 1) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][2] + 2) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][2] + 3) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][2] + 4) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][2] + 5) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[0][2] + 6) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
|
||||||
|
new (&a23[1][0]) int16_t;
|
||||||
|
new (&a23[1][0] + 1) int16_t;
|
||||||
|
new (&a23[1][0] + 2) int16_t;
|
||||||
|
new (&a23[1][0] + 3) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[1][0] + 4) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
|
||||||
|
new (&a23[1][1]) int16_t;
|
||||||
|
new (&a23[1][2]) int16_t;
|
||||||
|
new (&a23[1][2] + 1) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[1][3]) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[1][3] + 1) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
|
||||||
|
new (&a23[2][0]) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
new (&a23[2][0] + 1) int16_t; // { dg-warning "\\\[-Wplacement-new" }
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/* { dg-do compile }
|
/* { dg-do compile }
|
||||||
{ dg-options "-O2 -Wall" } */
|
{ dg-options "-O2 -Wall -Wno-stringop-overread" } */
|
||||||
|
|
||||||
typedef __SIZE_TYPE__ size_t;
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ void fa0_extern (void)
|
||||||
{
|
{
|
||||||
sink (strlen (ea0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
sink (strlen (ea0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||||
sink (strlen (ea0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
sink (strlen (ea0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||||
sink (strlen (ea0.a)); // { dg-warning "\\\[-Wstringop-overread" "pr93514" }
|
sink (strlen (ea0.a)); // valid just-past-the-end offset
|
||||||
sink (strlen (ea0.a + 1)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
sink (strlen (ea0.a + 1)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ void fa0_static (void)
|
||||||
{
|
{
|
||||||
sink (strlen (sa0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
sink (strlen (sa0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||||
sink (strlen (sa0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
sink (strlen (sa0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||||
sink (strlen (sa0.a)); // { dg-warning "\\\[-Wstringop-overread" "pr93514" }
|
sink (strlen (sa0.a)); // valid just-past-the-end offset
|
||||||
sink (strlen (sa0.a + 1)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
sink (strlen (sa0.a + 1)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,14 +52,14 @@ void fax_static (void)
|
||||||
sink (strlen (ax0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
sink (strlen (ax0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||||
sink (strlen (ax0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
sink (strlen (ax0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||||
sink (strlen (ax0.a));
|
sink (strlen (ax0.a));
|
||||||
sink (strlen (ax0.a + 1)); // { dg-warning "\\\[-Wstringop-overread" "pr93514" }
|
sink (strlen (ax0.a + 1)); // valid just-past-the-end offset
|
||||||
sink (strlen (ax0.a + 2)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
sink (strlen (ax0.a + 2)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
||||||
|
|
||||||
sink (strlen (ax1.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
sink (strlen (ax1.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||||
sink (strlen (ax1.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
sink (strlen (ax1.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||||
sink (strlen (ax1.a));
|
sink (strlen (ax1.a));
|
||||||
sink (strlen (ax1.a + 1));
|
sink (strlen (ax1.a + 1));
|
||||||
sink (strlen (ax1.a + 2)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" "pr93514" }
|
sink (strlen (ax1.a + 2)); // valid just-past-the-end offset
|
||||||
sink (strlen (ax1.a + 3)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
sink (strlen (ax1.a + 3)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
||||||
|
|
||||||
sink (strlen (ax2.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
sink (strlen (ax2.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||||
|
@ -67,7 +67,7 @@ void fax_static (void)
|
||||||
sink (strlen (ax2.a));
|
sink (strlen (ax2.a));
|
||||||
sink (strlen (ax2.a + 1));
|
sink (strlen (ax2.a + 1));
|
||||||
sink (strlen (ax2.a + 2));
|
sink (strlen (ax2.a + 2));
|
||||||
sink (strlen (ax2.a + 3)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" "pr93514" }
|
sink (strlen (ax2.a + 3)); // valid just-past-the-end offset
|
||||||
sink (strlen (ax2.a + 4)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
sink (strlen (ax2.a + 4)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
||||||
|
|
||||||
sink (strlen (ax3.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
sink (strlen (ax3.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||||
|
@ -76,6 +76,6 @@ void fax_static (void)
|
||||||
sink (strlen (ax3.a + 1));
|
sink (strlen (ax3.a + 1));
|
||||||
sink (strlen (ax3.a + 2));
|
sink (strlen (ax3.a + 2));
|
||||||
sink (strlen (ax3.a + 3));
|
sink (strlen (ax3.a + 3));
|
||||||
sink (strlen (ax3.a + 4)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" "pr93514" }
|
sink (strlen (ax3.a + 4)); // valid just-past-the-end offset
|
||||||
sink (strlen (ax3.a + 5)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
sink (strlen (ax3.a + 5)); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overread" }
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,6 +184,18 @@ void test_note (const char *s)
|
||||||
sink (a);
|
sink (a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char a[1][1][2]; // { dg-message "at offset 2 into " }
|
||||||
|
strncpy (a[0][1], s, 3); // { dg-warning "writing 3 bytes into a region of size 0 " }
|
||||||
|
sink (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char a[1][2][2]; // { dg-message "destination object" }
|
||||||
|
strncpy (a[0][0], s, 3); // { dg-warning "writing 3 bytes into a region of size 2 " }
|
||||||
|
sink (a);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
char a[1][2][2]; // { dg-message "at offset 2 into " }
|
char a[1][2][2]; // { dg-message "at offset 2 into " }
|
||||||
strncpy (a[0][1], s, 3); // { dg-warning "writing 3 bytes into a region of size 2 " }
|
strncpy (a[0][1], s, 3); // { dg-warning "writing 3 bytes into a region of size 2 " }
|
||||||
|
@ -192,7 +204,13 @@ void test_note (const char *s)
|
||||||
|
|
||||||
{
|
{
|
||||||
char a[1][2][2]; // { dg-message "at offset 4 into " }
|
char a[1][2][2]; // { dg-message "at offset 4 into " }
|
||||||
strncpy (a[1][0], s, 3); // { dg-warning "writing 3 bytes into a region of size 2 " }
|
strncpy (a[1][0], s, 3); // { dg-warning "writing 3 bytes into a region of size 0 " }
|
||||||
|
sink (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char a[2][1][2]; // { dg-message "at offset 2 into " }
|
||||||
|
strncpy (a[0][1], s, 3); // { dg-warning "writing 3 bytes into a region of size 0 " }
|
||||||
sink (a);
|
sink (a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
gcc/tree.c
36
gcc/tree.c
|
@ -13640,20 +13640,21 @@ get_initializer_for (tree init, tree decl)
|
||||||
/* Determines the size of the member referenced by the COMPONENT_REF
|
/* Determines the size of the member referenced by the COMPONENT_REF
|
||||||
REF, using its initializer expression if necessary in order to
|
REF, using its initializer expression if necessary in order to
|
||||||
determine the size of an initialized flexible array member.
|
determine the size of an initialized flexible array member.
|
||||||
If non-null, *INTERIOR_ZERO_LENGTH is set when REF refers to
|
If non-null, set *ARK when REF refers to an interior zero-length
|
||||||
an interior zero-length array.
|
array or a trailing one-element array.
|
||||||
Returns the size as sizetype (which might be zero for an object
|
Returns the size as sizetype (which might be zero for an object
|
||||||
with an uninitialized flexible array member) or null if the size
|
with an uninitialized flexible array member) or null if the size
|
||||||
cannot be determined. */
|
cannot be determined. */
|
||||||
|
|
||||||
tree
|
tree
|
||||||
component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
component_ref_size (tree ref, special_array_member *sam /* = NULL */)
|
||||||
{
|
{
|
||||||
gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
|
gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
|
||||||
|
|
||||||
bool int_0_len = false;
|
special_array_member arkbuf;
|
||||||
if (!interior_zero_length)
|
if (!sam)
|
||||||
interior_zero_length = &int_0_len;
|
sam = &arkbuf;
|
||||||
|
*sam = special_array_member::none;
|
||||||
|
|
||||||
/* The object/argument referenced by the COMPONENT_REF and its type. */
|
/* The object/argument referenced by the COMPONENT_REF and its type. */
|
||||||
tree arg = TREE_OPERAND (ref, 0);
|
tree arg = TREE_OPERAND (ref, 0);
|
||||||
|
@ -13675,9 +13676,16 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
||||||
more than one element. */
|
more than one element. */
|
||||||
return memsize;
|
return memsize;
|
||||||
|
|
||||||
*interior_zero_length = zero_length && !trailing;
|
if (zero_length)
|
||||||
if (*interior_zero_length)
|
{
|
||||||
|
if (trailing)
|
||||||
|
*sam = special_array_member::trail_0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*sam = special_array_member::int_0;
|
||||||
memsize = NULL_TREE;
|
memsize = NULL_TREE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!zero_length)
|
if (!zero_length)
|
||||||
if (tree dom = TYPE_DOMAIN (memtype))
|
if (tree dom = TYPE_DOMAIN (memtype))
|
||||||
|
@ -13688,9 +13696,13 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
||||||
{
|
{
|
||||||
offset_int minidx = wi::to_offset (min);
|
offset_int minidx = wi::to_offset (min);
|
||||||
offset_int maxidx = wi::to_offset (max);
|
offset_int maxidx = wi::to_offset (max);
|
||||||
if (maxidx - minidx > 0)
|
offset_int neltsm1 = maxidx - minidx;
|
||||||
|
if (neltsm1 > 0)
|
||||||
/* MEMBER is an array with more than one element. */
|
/* MEMBER is an array with more than one element. */
|
||||||
return memsize;
|
return memsize;
|
||||||
|
|
||||||
|
if (neltsm1 == 0)
|
||||||
|
*sam = special_array_member::trail_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For a refernce to a zero- or one-element array member of a union
|
/* For a refernce to a zero- or one-element array member of a union
|
||||||
|
@ -13708,7 +13720,7 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
||||||
tree base = get_addr_base_and_unit_offset (ref, &baseoff);
|
tree base = get_addr_base_and_unit_offset (ref, &baseoff);
|
||||||
if (!base || !VAR_P (base))
|
if (!base || !VAR_P (base))
|
||||||
{
|
{
|
||||||
if (!*interior_zero_length)
|
if (*sam != special_array_member::int_0)
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
|
|
||||||
if (TREE_CODE (arg) != COMPONENT_REF)
|
if (TREE_CODE (arg) != COMPONENT_REF)
|
||||||
|
@ -13728,7 +13740,7 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
||||||
/* Determine the base type of the referenced object. If it's
|
/* Determine the base type of the referenced object. If it's
|
||||||
the same as ARGTYPE and MEMBER has a known size, return it. */
|
the same as ARGTYPE and MEMBER has a known size, return it. */
|
||||||
tree bt = basetype;
|
tree bt = basetype;
|
||||||
if (!*interior_zero_length)
|
if (*sam != special_array_member::int_0)
|
||||||
while (TREE_CODE (bt) == ARRAY_TYPE)
|
while (TREE_CODE (bt) == ARRAY_TYPE)
|
||||||
bt = TREE_TYPE (bt);
|
bt = TREE_TYPE (bt);
|
||||||
bool typematch = useless_type_conversion_p (argtype, bt);
|
bool typematch = useless_type_conversion_p (argtype, bt);
|
||||||
|
@ -13768,7 +13780,7 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
||||||
if (DECL_P (base)
|
if (DECL_P (base)
|
||||||
&& DECL_EXTERNAL (base)
|
&& DECL_EXTERNAL (base)
|
||||||
&& bt == basetype
|
&& bt == basetype
|
||||||
&& !*interior_zero_length)
|
&& *sam != special_array_member::int_0)
|
||||||
/* The size of a flexible array member of an extern struct
|
/* The size of a flexible array member of an extern struct
|
||||||
with no initializer cannot be determined (it's defined
|
with no initializer cannot be determined (it's defined
|
||||||
in another translation unit and can have an initializer
|
in another translation unit and can have an initializer
|
||||||
|
|
12
gcc/tree.h
12
gcc/tree.h
|
@ -5292,12 +5292,22 @@ extern bool array_at_struct_end_p (tree);
|
||||||
by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
|
by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
|
||||||
extern tree component_ref_field_offset (tree);
|
extern tree component_ref_field_offset (tree);
|
||||||
|
|
||||||
|
/* Describes a "special" array member due to which component_ref_size
|
||||||
|
returns null. */
|
||||||
|
enum struct special_array_member
|
||||||
|
{
|
||||||
|
none, /* Not a special array member. */
|
||||||
|
int_0, /* Interior array member with size zero. */
|
||||||
|
trail_0, /* Trailing array member with size zero. */
|
||||||
|
trail_1 /* Trailing array member with one element. */
|
||||||
|
};
|
||||||
|
|
||||||
/* Return the size of the member referenced by the COMPONENT_REF, using
|
/* Return the size of the member referenced by the COMPONENT_REF, using
|
||||||
its initializer expression if necessary in order to determine the size
|
its initializer expression if necessary in order to determine the size
|
||||||
of an initialized flexible array member. The size might be zero for
|
of an initialized flexible array member. The size might be zero for
|
||||||
an object with an uninitialized flexible array member or null if it
|
an object with an uninitialized flexible array member or null if it
|
||||||
cannot be determined. */
|
cannot be determined. */
|
||||||
extern tree component_ref_size (tree, bool * = NULL);
|
extern tree component_ref_size (tree, special_array_member * = NULL);
|
||||||
|
|
||||||
extern int tree_map_base_eq (const void *, const void *);
|
extern int tree_map_base_eq (const void *, const void *);
|
||||||
extern unsigned int tree_map_base_hash (const void *);
|
extern unsigned int tree_map_base_hash (const void *);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue