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 */,
|
||||
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,26 +4434,29 @@ 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;
|
||||
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;
|
||||
}
|
||||
|
||||
const tree_code code = TREE_CODE (ptr);
|
||||
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!size || TREE_CODE (size) != INTEGER_CST)
|
||||
return false;
|
||||
|
||||
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
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -173,6 +173,22 @@ struct access_ref
|
|||
For string functions the size of the actual access is
|
||||
further constrained by the length of the string. */
|
||||
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
|
||||
|
|
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 "asan.h"
|
||||
#include "stor-layout.h"
|
||||
#include "builtins.h"
|
||||
|
||||
static bool begin_init_stmts (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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
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
|
||||
|
@ -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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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. */
|
||||
size = fold_non_dependent_expr (size);
|
||||
|
||||
/* Handle the common case of array + offset expression when the offset
|
||||
is a constant. */
|
||||
if (TREE_CODE (oper) == POINTER_PLUS_EXPR)
|
||||
{
|
||||
/* If the offset is compile-time constant, use it to compute a more
|
||||
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)
|
||||
access_ref ref;
|
||||
ref.eval = [](tree x){ return fold_non_dependent_expr (x); };
|
||||
ref.trail1special = warn_placement_new < 2;
|
||||
tree objsize = compute_objsize (oper, 1, &ref);
|
||||
if (!objsize)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reduce the size of the buffer by the adjustment computed above
|
||||
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_avail = wi::to_offset (objsize);
|
||||
offset_int bytes_need;
|
||||
|
||||
if (nelts)
|
||||
nelts = fold_for_warn (nelts);
|
||||
|
||||
if (CONSTANT_CLASS_P (size))
|
||||
bytes_need = wi::to_offset (size);
|
||||
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;
|
||||
}
|
||||
|
||||
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 (CONSTANT_CLASS_P (nelts))
|
||||
warning_at (loc, OPT_Wplacement_new_,
|
||||
exact_size ?
|
||||
"placement new constructing an object of type "
|
||||
"%<%T [%wu]%> and size %qwu in a region of type %qT "
|
||||
"and size %qwi"
|
||||
: "placement new constructing an object of type "
|
||||
"%<%T [%wu]%> and size %qwu in a region of type %qT "
|
||||
"and size at most %qwu",
|
||||
type, tree_to_uhwi (nelts), bytes_need.to_uhwi (),
|
||||
warned = warning_at (loc, OPT_Wplacement_new_,
|
||||
(exact_size
|
||||
? G_("placement new constructing an object "
|
||||
"of type %<%T [%wu]%> and size %qwu "
|
||||
"in a region of type %qT and size %qwi")
|
||||
: G_("placement new constructing an object "
|
||||
"of type %<%T [%wu]%> and size %qwu "
|
||||
"in a region of type %qT and size "
|
||||
"at most %qwu")),
|
||||
type, tree_to_uhwi (nelts),
|
||||
bytes_need.to_uhwi (),
|
||||
opertype, bytes_avail.to_uhwi ());
|
||||
else
|
||||
warning_at (loc, OPT_Wplacement_new_,
|
||||
exact_size ?
|
||||
"placement new constructing an array of objects "
|
||||
"of type %qT and size %qwu in a region of type %qT "
|
||||
"and size %qwi"
|
||||
: "placement new constructing an array of objects "
|
||||
"of type %qT and size %qwu in a region of type %qT "
|
||||
"and size at most %qwu",
|
||||
warned = warning_at (loc, OPT_Wplacement_new_,
|
||||
(exact_size
|
||||
? G_("placement new constructing an array "
|
||||
"of objects of type %qT and size %qwu "
|
||||
"in a region of type %qT and size %qwi")
|
||||
: G_("placement new constructing an array "
|
||||
"of objects of type %qT and size %qwu "
|
||||
"in a region of type %qT and size "
|
||||
"at most %qwu")),
|
||||
type, bytes_need.to_uhwi (), opertype,
|
||||
bytes_avail.to_uhwi ());
|
||||
else
|
||||
warning_at (loc, OPT_Wplacement_new_,
|
||||
exact_size ?
|
||||
"placement new constructing an object of type %qT "
|
||||
"and size %qwu in a region of type %qT and size %qwi"
|
||||
: "placement new constructing an object of type %qT "
|
||||
"and size %qwu in a region of type %qT and size "
|
||||
"at most %qwu",
|
||||
warned = warning_at (loc, OPT_Wplacement_new_,
|
||||
(exact_size
|
||||
? G_("placement new constructing an object "
|
||||
"of type %qT and size %qwu in a region "
|
||||
"of type %qT and size %qwi")
|
||||
: G_("placement new constructing an object "
|
||||
"of type %qT "
|
||||
"and size %qwu in a region of type %qT "
|
||||
"and size at most %qwu")),
|
||||
type, bytes_need.to_uhwi (), opertype,
|
||||
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__. */
|
||||
|
|
|
@ -188,7 +188,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
|
|||
tree decl = NULL_TREE;
|
||||
|
||||
/* Set for accesses to interior zero-length arrays. */
|
||||
bool interior_zero_len = false;
|
||||
special_array_member sam{ };
|
||||
|
||||
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
|
||||
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)
|
||||
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",
|
||||
low_sub, artype);
|
||||
|
||||
if (!warned && interior_zero_len)
|
||||
if (!warned && sam == special_array_member::int_0)
|
||||
warned = warning_at (location, OPT_Wzero_length_bounds,
|
||||
(TREE_CODE (low_sub) == INTEGER_CST
|
||||
? 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.
|
||||
// If/when GIMPLE changes to make this possible this test can be
|
||||
// removed.
|
||||
char *q = new (p->a) char [16];
|
||||
char *q = new (p->a) char [16]; // { dg-warning "\\\[-Wplacement-new" }
|
||||
|
||||
init (q);
|
||||
|
||||
|
|
|
@ -66,8 +66,9 @@ struct BA2 { int i; A2 a2; };
|
|||
void fBx (BAx *pbx, BAx &rbx)
|
||||
{
|
||||
BAx bax;
|
||||
new (bax.ax.a) char; // { dg-warning "placement" }
|
||||
new (bax.ax.a) Int16; // { dg-warning "placement" }
|
||||
// The uninitialized flexible array takes up the bytes of padding.
|
||||
new (bax.ax.a) char;
|
||||
new (bax.ax.a) Int16;
|
||||
new (bax.ax.a) Int32; // { dg-warning "placement" }
|
||||
|
||||
new (pbx->ax.a) char;
|
||||
|
@ -84,9 +85,12 @@ void fBx1 ()
|
|||
{
|
||||
static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } };
|
||||
|
||||
new (bax1.ax.a) char; // { dg-warning "placement" }
|
||||
new (bax1.ax.a) char[2]; // { dg-warning "placement" }
|
||||
new (bax1.ax.a) Int16; // { dg-warning "placement" }
|
||||
// The empty flexible array takes up the bytes of padding.
|
||||
new (bax1.ax.a) char;
|
||||
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" }
|
||||
}
|
||||
|
||||
|
|
|
@ -124,9 +124,13 @@ struct BA2 { int i; A2 a2; };
|
|||
void fBx (BAx *pbx, BAx &rbx)
|
||||
{
|
||||
BAx bax;
|
||||
new (bax.ax.a) char; // { dg-warning "placement" }
|
||||
new (bax.ax.a) Int16; // { dg-warning "placement" }
|
||||
// The uninitialized flexible array takes up the bytes of padding.
|
||||
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) char[4]; // { dg-warning "placement" }
|
||||
new (bax.ax.a) char[5]; // { dg-warning "placement" }
|
||||
|
||||
new (pbx->ax.a) char;
|
||||
new (rbx.ax.a) char;
|
||||
|
@ -142,10 +146,14 @@ void fBx1 ()
|
|||
{
|
||||
static BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } };
|
||||
|
||||
new (bax1.ax.a) char; // { dg-warning "placement" }
|
||||
new (bax1.ax.a) char[2]; // { dg-warning "placement" }
|
||||
new (bax1.ax.a) Int16; // { dg-warning "placement" }
|
||||
// The empty flexible array takes up the bytes of padding.
|
||||
new (bax1.ax.a) char;
|
||||
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) char[4]; // { dg-warning "placement" }
|
||||
new (bax1.ax.a) char[5]; // { dg-warning "placement" }
|
||||
}
|
||||
|
||||
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" }
|
||||
|
||||
new (bax1.ax.a) char; // { dg-warning "placement" }
|
||||
new (bax1.ax.a) char[2]; // { dg-warning "placement" }
|
||||
new (bax1.ax.a) Int16; // { dg-warning "placement" }
|
||||
// The first three bytes of the flexible array member live in the padding.
|
||||
new (bax1.ax.a) char;
|
||||
new (bax1.ax.a) char[2];
|
||||
new (bax1.ax.a) Int16;
|
||||
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" }
|
||||
|
||||
new (bax2.ax.a) char; // { dg-warning "placement" }
|
||||
new (bax2.ax.a) char[2]; // { dg-warning "placement" }
|
||||
new (bax2.ax.a) char[3]; // { dg-warning "placement" }
|
||||
new (bax2.ax.a) Int16; // { dg-warning "placement" }
|
||||
// The first three bytes of the flexible array member live in the padding.
|
||||
new (bax2.ax.a) char;
|
||||
new (bax2.ax.a) char[2];
|
||||
new (bax2.ax.a) char[3];
|
||||
new (bax2.ax.a) Int16;
|
||||
new (bax2.ax.a) char[4]; // { 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" }
|
||||
|
||||
new (bax2.ax.a) char; // { dg-warning "placement" }
|
||||
new (bax2.ax.a) char[2]; // { dg-warning "placement" }
|
||||
new (bax2.ax.a) Int16; // { dg-warning "placement" }
|
||||
new (bax2.ax.a) char[3]; // { dg-warning "placement" }
|
||||
// The first three bytes of the flexible array member live in the padding.
|
||||
new (bax2.ax.a) char;
|
||||
new (bax2.ax.a) char[2];
|
||||
new (bax2.ax.a) Int16;
|
||||
new (bax2.ax.a) char[3];
|
||||
new (bax2.ax.a) char[4]; // { 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-options "-O2 -Wall" } */
|
||||
{ dg-options "-O2 -Wall -Wno-stringop-overread" } */
|
||||
|
||||
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 - 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" }
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ void fa0_static (void)
|
|||
{
|
||||
sink (strlen (sa0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
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" }
|
||||
}
|
||||
|
||||
|
@ -52,14 +52,14 @@ void fax_static (void)
|
|||
sink (strlen (ax0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
sink (strlen (ax0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
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 (ax1.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
sink (strlen (ax1.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax1.a));
|
||||
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 (ax2.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
|
@ -67,7 +67,7 @@ void fax_static (void)
|
|||
sink (strlen (ax2.a));
|
||||
sink (strlen (ax2.a + 1));
|
||||
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 (ax3.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
|
@ -76,6 +76,6 @@ void fax_static (void)
|
|||
sink (strlen (ax3.a + 1));
|
||||
sink (strlen (ax3.a + 2));
|
||||
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" }
|
||||
}
|
||||
|
|
|
@ -184,6 +184,18 @@ void test_note (const char *s)
|
|||
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 " }
|
||||
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 " }
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
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
|
||||
REF, using its initializer expression if necessary in order to
|
||||
determine the size of an initialized flexible array member.
|
||||
If non-null, *INTERIOR_ZERO_LENGTH is set when REF refers to
|
||||
an interior zero-length array.
|
||||
If non-null, set *ARK when REF refers to an interior zero-length
|
||||
array or a trailing one-element array.
|
||||
Returns the size as sizetype (which might be zero for an object
|
||||
with an uninitialized flexible array member) or null if the size
|
||||
cannot be determined. */
|
||||
|
||||
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);
|
||||
|
||||
bool int_0_len = false;
|
||||
if (!interior_zero_length)
|
||||
interior_zero_length = &int_0_len;
|
||||
special_array_member arkbuf;
|
||||
if (!sam)
|
||||
sam = &arkbuf;
|
||||
*sam = special_array_member::none;
|
||||
|
||||
/* The object/argument referenced by the COMPONENT_REF and its type. */
|
||||
tree arg = TREE_OPERAND (ref, 0);
|
||||
|
@ -13675,9 +13676,16 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
|||
more than one element. */
|
||||
return memsize;
|
||||
|
||||
*interior_zero_length = zero_length && !trailing;
|
||||
if (*interior_zero_length)
|
||||
if (zero_length)
|
||||
{
|
||||
if (trailing)
|
||||
*sam = special_array_member::trail_0;
|
||||
else
|
||||
{
|
||||
*sam = special_array_member::int_0;
|
||||
memsize = NULL_TREE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zero_length)
|
||||
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 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. */
|
||||
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
|
||||
|
@ -13708,7 +13720,7 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
|||
tree base = get_addr_base_and_unit_offset (ref, &baseoff);
|
||||
if (!base || !VAR_P (base))
|
||||
{
|
||||
if (!*interior_zero_length)
|
||||
if (*sam != special_array_member::int_0)
|
||||
return NULL_TREE;
|
||||
|
||||
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
|
||||
the same as ARGTYPE and MEMBER has a known size, return it. */
|
||||
tree bt = basetype;
|
||||
if (!*interior_zero_length)
|
||||
if (*sam != special_array_member::int_0)
|
||||
while (TREE_CODE (bt) == ARRAY_TYPE)
|
||||
bt = TREE_TYPE (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)
|
||||
&& DECL_EXTERNAL (base)
|
||||
&& bt == basetype
|
||||
&& !*interior_zero_length)
|
||||
&& *sam != special_array_member::int_0)
|
||||
/* The size of a flexible array member of an extern struct
|
||||
with no initializer cannot be determined (it's defined
|
||||
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. */
|
||||
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
|
||||
its initializer expression if necessary in order to determine the size
|
||||
of an initialized flexible array member. The size might be zero for
|
||||
an object with an uninitialized flexible array member or null if it
|
||||
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 unsigned int tree_map_base_hash (const void *);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue