Commit 9ca1eaac by Martin Sebor Committed by Martin Sebor

PR c++/83058 - ICE on C++ code with negative array index: in warn_placement_new_too_small

gcc/cp/ChangeLog:

	PR c++/83058
	* init.c (warn_placement_new_too_small): Use offset_int instead of
	HOST_WIDE_INT.

gcc/testsuite/ChangeLog:

	PR c++/83058
	* g++.dg/warn/Wplacement-new-size-5.C: New test.

From-SVN: r255182
parent de3d4fd0
2017-11-27 Martin Sebor <msebor@redhat.com>
PR c++/83058
* init.c (warn_placement_new_too_small): Use offset_int instead of
HOST_WIDE_INT.
2017-11-27 Jakub Jelinek <jakub@redhat.com> 2017-11-27 Jakub Jelinek <jakub@redhat.com>
PR c++/81888 PR c++/81888
......
...@@ -2498,9 +2498,9 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2498,9 +2498,9 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
/* The number of bytes to add to or subtract from the size of the provided /* 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. buffer based on an offset into an array or an array element reference.
Although intermediate results may be negative (as in a[3] - 2) the final Although intermediate results may be negative (as in a[3] - 2) a valid
result cannot be. */ final result cannot be. */
HOST_WIDE_INT adjust = 0; offset_int adjust = 0;
/* True when the size of the entire destination object should be used /* True when the size of the entire destination object should be used
to compute the possibly optimistic estimate of the available space. */ to compute the possibly optimistic estimate of the available space. */
bool use_obj_size = false; bool use_obj_size = false;
...@@ -2524,7 +2524,7 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2524,7 +2524,7 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
is a constant. */ is a constant. */
if (TREE_CODE (oper) == POINTER_PLUS_EXPR) if (TREE_CODE (oper) == POINTER_PLUS_EXPR)
{ {
/* If the offset is comple-time constant, use it to compute a more /* If the offset is compile-time constant, use it to compute a more
accurate estimate of the size of the buffer. Since the operand accurate estimate of the size of the buffer. Since the operand
of POINTER_PLUS_EXPR is represented as an unsigned type, convert of POINTER_PLUS_EXPR is represented as an unsigned type, convert
it to signed first. it to signed first.
...@@ -2532,7 +2532,7 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2532,7 +2532,7 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
estimate (this may lead to false negatives). */ estimate (this may lead to false negatives). */
tree adj = TREE_OPERAND (oper, 1); tree adj = TREE_OPERAND (oper, 1);
if (CONSTANT_CLASS_P (adj)) if (CONSTANT_CLASS_P (adj))
adjust += tree_to_shwi (convert (ssizetype, adj)); adjust += wi::to_offset (convert (ssizetype, adj));
else else
use_obj_size = true; use_obj_size = true;
...@@ -2559,9 +2559,9 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2559,9 +2559,9 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
not a compile-time constant, use the index to determine the not a compile-time constant, use the index to determine the
size of the buffer. Otherwise, use the entire array as size of the buffer. Otherwise, use the entire array as
an optimistic estimate of the size. */ an optimistic estimate of the size. */
const_tree adj = TREE_OPERAND (oper, 1); const_tree adj = fold_non_dependent_expr (TREE_OPERAND (oper, 1));
if (!use_obj_size && CONSTANT_CLASS_P (adj)) if (!use_obj_size && CONSTANT_CLASS_P (adj))
adjust += tree_to_shwi (adj); adjust += wi::to_offset (adj);
else else
{ {
use_obj_size = true; use_obj_size = true;
...@@ -2580,10 +2580,18 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2580,10 +2580,18 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
members from arrays of unspecified size. */ members from arrays of unspecified size. */
bool compref = TREE_CODE (oper) == COMPONENT_REF; 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 /* Descend into a struct or union to find the member whose address
is being used as the argument. */ is being used as the argument. */
if (TREE_CODE (oper) == COMPONENT_REF) 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; tree op0 = oper;
while (TREE_CODE (op0 = TREE_OPERAND (op0, 0)) == COMPONENT_REF); while (TREE_CODE (op0 = TREE_OPERAND (op0, 0)) == COMPONENT_REF);
if (VAR_P (op0)) if (VAR_P (op0))
...@@ -2591,14 +2599,15 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2591,14 +2599,15 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
oper = TREE_OPERAND (oper, 1); oper = TREE_OPERAND (oper, 1);
} }
if ((addr_expr || !POINTER_TYPE_P (TREE_TYPE (oper))) tree opertype = TREE_TYPE (oper);
if ((addr_expr || !POINTER_TYPE_P (opertype))
&& (VAR_P (oper) && (VAR_P (oper)
|| TREE_CODE (oper) == FIELD_DECL || TREE_CODE (oper) == FIELD_DECL
|| TREE_CODE (oper) == PARM_DECL)) || TREE_CODE (oper) == PARM_DECL))
{ {
/* A possibly optimistic estimate of the number of bytes available /* A possibly optimistic estimate of the number of bytes available
in the destination buffer. */ in the destination buffer. */
unsigned HOST_WIDE_INT bytes_avail = 0; offset_int bytes_avail = 0;
/* True when the estimate above is in fact the exact size /* True when the estimate above is in fact the exact size
of the destination buffer rather than an estimate. */ of the destination buffer rather than an estimate. */
bool exact_size = true; bool exact_size = true;
...@@ -2613,47 +2622,42 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2613,47 +2622,42 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
/* Use the size of the entire array object when the expression /* Use the size of the entire array object when the expression
refers to a variable or its size depends on an expression refers to a variable or its size depends on an expression
that's not a compile-time constant. */ that's not a compile-time constant. */
bytes_avail = tree_to_uhwi (DECL_SIZE_UNIT (oper)); bytes_avail = wi::to_offset (DECL_SIZE_UNIT (oper));
exact_size = !use_obj_size; exact_size = !use_obj_size;
} }
else if (TYPE_SIZE_UNIT (TREE_TYPE (oper)) else if (tree opersize = TYPE_SIZE_UNIT (opertype))
&& tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (oper))))
{ {
/* Use the size of the type of the destination buffer object /* Use the size of the type of the destination buffer object
as the optimistic estimate of the available space in it. */ as the optimistic estimate of the available space in it.
bytes_avail = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (oper))); 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);
} }
else if (var_decl)
{ if (bytes_avail == 0)
/* 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. */
bytes_avail = 0;
if (tree init = find_field_init (oper, DECL_INITIAL (var_decl)))
bytes_avail = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (init)));
}
else
{ {
/* Bail if neither the size of the object nor its type is known. */ if (var_decl)
return; {
/* 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_field_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 (TREE_TYPE (oper)); tree_code oper_code = TREE_CODE (opertype);
if (compref && oper_code == ARRAY_TYPE) if (compref && oper_code == ARRAY_TYPE)
{ {
/* Avoid diagnosing flexible array members (which are accepted tree nelts = array_type_nelts_top (opertype);
as an extension and diagnosed with -Wpedantic) and zero-length
arrays (also an extension).
Overflowing construction in one-element arrays is diagnosed
only at level 2. */
if (bytes_avail == 0 && !var_decl)
return;
tree nelts = array_type_nelts_top (TREE_TYPE (oper));
tree nelts_cst = maybe_constant_value (nelts); tree nelts_cst = maybe_constant_value (nelts);
if (TREE_CODE (nelts_cst) == INTEGER_CST if (TREE_CODE (nelts_cst) == INTEGER_CST
&& integer_onep (nelts_cst) && integer_onep (nelts_cst)
...@@ -2662,29 +2666,35 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2662,29 +2666,35 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
return; return;
} }
/* The size of the buffer can only be adjusted down but not up. */
gcc_checking_assert (0 <= adjust);
/* Reduce the size of the buffer by the adjustment computed above /* Reduce the size of the buffer by the adjustment computed above
from the offset and/or the index into the array. */ from the offset and/or the index into the array. */
if (bytes_avail < static_cast<unsigned HOST_WIDE_INT>(adjust)) if (bytes_avail < adjust || adjust < 0)
bytes_avail = 0; bytes_avail = 0;
else else
bytes_avail -= adjust; {
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 /* The minimum amount of space needed for the allocation. This
is an optimistic estimate that makes it possible to detect is an optimistic estimate that makes it possible to detect
placement new invocation for some undersize buffers but not placement new invocation for some undersize buffers but not
others. */ others. */
unsigned HOST_WIDE_INT bytes_need; offset_int bytes_need;
if (CONSTANT_CLASS_P (size)) if (CONSTANT_CLASS_P (size))
bytes_need = tree_to_uhwi (size); bytes_need = wi::to_offset (size);
else if (nelts && CONSTANT_CLASS_P (nelts)) else if (nelts && CONSTANT_CLASS_P (nelts))
bytes_need = tree_to_uhwi (nelts) bytes_need = (wi::to_offset (nelts)
* tree_to_uhwi (TYPE_SIZE_UNIT (type)); * wi::to_offset (TYPE_SIZE_UNIT (type)));
else if (tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))) else if (tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
bytes_need = tree_to_uhwi (TYPE_SIZE_UNIT (type)); bytes_need = wi::to_offset (TYPE_SIZE_UNIT (type));
else else
{ {
/* The type is a VLA. */ /* The type is a VLA. */
...@@ -2703,9 +2713,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2703,9 +2713,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
: "placement new constructing an object of type " : "placement new constructing an object of type "
"%<%T [%wu]%> and size %qwu in a region of type %qT " "%<%T [%wu]%> and size %qwu in a region of type %qT "
"and size at most %qwu", "and size at most %qwu",
type, tree_to_uhwi (nelts), bytes_need, type, tree_to_uhwi (nelts), bytes_need.to_uhwi (),
TREE_TYPE (oper), opertype, bytes_avail.to_uhwi ());
bytes_avail);
else else
warning_at (loc, OPT_Wplacement_new_, warning_at (loc, OPT_Wplacement_new_,
exact_size ? exact_size ?
...@@ -2715,8 +2724,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2715,8 +2724,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
: "placement new constructing an array of objects " : "placement new constructing an array of objects "
"of type %qT and size %qwu in a region of type %qT " "of type %qT and size %qwu in a region of type %qT "
"and size at most %qwu", "and size at most %qwu",
type, bytes_need, TREE_TYPE (oper), type, bytes_need.to_uhwi (), opertype,
bytes_avail); bytes_avail.to_uhwi ());
else else
warning_at (loc, OPT_Wplacement_new_, warning_at (loc, OPT_Wplacement_new_,
exact_size ? exact_size ?
...@@ -2725,8 +2734,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) ...@@ -2725,8 +2734,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
: "placement new constructing an object of type %qT " : "placement new constructing an object of type %qT "
"and size %qwu in a region of type %qT and size " "and size %qwu in a region of type %qT and size "
"at most %qwu", "at most %qwu",
type, bytes_need, TREE_TYPE (oper), type, bytes_need.to_uhwi (), opertype,
bytes_avail); bytes_avail.to_uhwi ());
} }
} }
} }
......
2017-11-27 Martin Sebor <msebor@redhat.com>
PR c++/83058
* g++.dg/warn/Wplacement-new-size-5.C: New test.
2017-11-27 Jakub Jelinek <jakub@redhat.com> 2017-11-27 Jakub Jelinek <jakub@redhat.com>
PR c++/81888 PR c++/81888
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment