Skip to content

Commit 1a53b26

Browse files
author
msebor
committed
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@255182 138bc75d-0d04-0410-961f-82ee72b054a4
1 parent bdc0472 commit 1a53b26

File tree

4 files changed

+317
-56
lines changed

4 files changed

+317
-56
lines changed

gcc/cp/ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
2017-11-27 Martin Sebor <[email protected]>
2+
3+
PR c++/83058
4+
* init.c (warn_placement_new_too_small): Use offset_int instead of
5+
HOST_WIDE_INT.
6+
17
2017-11-27 Jakub Jelinek <[email protected]>
28

39
PR c++/81888

gcc/cp/init.c

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2498,9 +2498,9 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
24982498

24992499
/* The number of bytes to add to or subtract from the size of the provided
25002500
buffer based on an offset into an array or an array element reference.
2501-
Although intermediate results may be negative (as in a[3] - 2) the final
2502-
result cannot be. */
2503-
HOST_WIDE_INT adjust = 0;
2501+
Although intermediate results may be negative (as in a[3] - 2) a valid
2502+
final result cannot be. */
2503+
offset_int adjust = 0;
25042504
/* True when the size of the entire destination object should be used
25052505
to compute the possibly optimistic estimate of the available space. */
25062506
bool use_obj_size = false;
@@ -2524,15 +2524,15 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
25242524
is a constant. */
25252525
if (TREE_CODE (oper) == POINTER_PLUS_EXPR)
25262526
{
2527-
/* If the offset is comple-time constant, use it to compute a more
2527+
/* If the offset is compile-time constant, use it to compute a more
25282528
accurate estimate of the size of the buffer. Since the operand
25292529
of POINTER_PLUS_EXPR is represented as an unsigned type, convert
25302530
it to signed first.
25312531
Otherwise, use the size of the entire array as an optimistic
25322532
estimate (this may lead to false negatives). */
25332533
tree adj = TREE_OPERAND (oper, 1);
25342534
if (CONSTANT_CLASS_P (adj))
2535-
adjust += tree_to_shwi (convert (ssizetype, adj));
2535+
adjust += wi::to_offset (convert (ssizetype, adj));
25362536
else
25372537
use_obj_size = true;
25382538

@@ -2559,9 +2559,9 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
25592559
not a compile-time constant, use the index to determine the
25602560
size of the buffer. Otherwise, use the entire array as
25612561
an optimistic estimate of the size. */
2562-
const_tree adj = TREE_OPERAND (oper, 1);
2562+
const_tree adj = fold_non_dependent_expr (TREE_OPERAND (oper, 1));
25632563
if (!use_obj_size && CONSTANT_CLASS_P (adj))
2564-
adjust += tree_to_shwi (adj);
2564+
adjust += wi::to_offset (adj);
25652565
else
25662566
{
25672567
use_obj_size = true;
@@ -2580,25 +2580,34 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
25802580
members from arrays of unspecified size. */
25812581
bool compref = TREE_CODE (oper) == COMPONENT_REF;
25822582

2583+
/* For COMPONENT_REF (i.e., a struct member) the size of the entire
2584+
enclosing struct. Used to validate the adjustment (offset) into
2585+
an array at the end of a struct. */
2586+
offset_int compsize = 0;
2587+
25832588
/* Descend into a struct or union to find the member whose address
25842589
is being used as the argument. */
25852590
if (TREE_CODE (oper) == COMPONENT_REF)
25862591
{
2592+
tree comptype = TREE_TYPE (TREE_OPERAND (oper, 0));
2593+
compsize = wi::to_offset (TYPE_SIZE_UNIT (comptype));
2594+
25872595
tree op0 = oper;
25882596
while (TREE_CODE (op0 = TREE_OPERAND (op0, 0)) == COMPONENT_REF);
25892597
if (VAR_P (op0))
25902598
var_decl = op0;
25912599
oper = TREE_OPERAND (oper, 1);
25922600
}
25932601

2594-
if ((addr_expr || !POINTER_TYPE_P (TREE_TYPE (oper)))
2602+
tree opertype = TREE_TYPE (oper);
2603+
if ((addr_expr || !POINTER_TYPE_P (opertype))
25952604
&& (VAR_P (oper)
25962605
|| TREE_CODE (oper) == FIELD_DECL
25972606
|| TREE_CODE (oper) == PARM_DECL))
25982607
{
25992608
/* A possibly optimistic estimate of the number of bytes available
26002609
in the destination buffer. */
2601-
unsigned HOST_WIDE_INT bytes_avail = 0;
2610+
offset_int bytes_avail = 0;
26022611
/* True when the estimate above is in fact the exact size
26032612
of the destination buffer rather than an estimate. */
26042613
bool exact_size = true;
@@ -2613,47 +2622,42 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
26132622
/* Use the size of the entire array object when the expression
26142623
refers to a variable or its size depends on an expression
26152624
that's not a compile-time constant. */
2616-
bytes_avail = tree_to_uhwi (DECL_SIZE_UNIT (oper));
2625+
bytes_avail = wi::to_offset (DECL_SIZE_UNIT (oper));
26172626
exact_size = !use_obj_size;
26182627
}
2619-
else if (TYPE_SIZE_UNIT (TREE_TYPE (oper))
2620-
&& tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (oper))))
2628+
else if (tree opersize = TYPE_SIZE_UNIT (opertype))
26212629
{
26222630
/* Use the size of the type of the destination buffer object
2623-
as the optimistic estimate of the available space in it. */
2624-
bytes_avail = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (oper)));
2631+
as the optimistic estimate of the available space in it.
2632+
Use the maximum possible size for zero-size arrays and
2633+
flexible array members (except of initialized objects
2634+
thereof). */
2635+
if (TREE_CODE (opersize) == INTEGER_CST)
2636+
bytes_avail = wi::to_offset (opersize);
26252637
}
2626-
else if (var_decl)
2627-
{
2628-
/* Constructing into a buffer provided by the flexible array
2629-
member of a declared object (which is permitted as a G++
2630-
extension). If the array member has been initialized,
2631-
determine its size from the initializer. Otherwise,
2632-
the array size is zero. */
2633-
bytes_avail = 0;
2634-
2635-
if (tree init = find_field_init (oper, DECL_INITIAL (var_decl)))
2636-
bytes_avail = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (init)));
2637-
}
2638-
else
2638+
2639+
if (bytes_avail == 0)
26392640
{
2640-
/* Bail if neither the size of the object nor its type is known. */
2641-
return;
2641+
if (var_decl)
2642+
{
2643+
/* Constructing into a buffer provided by the flexible array
2644+
member of a declared object (which is permitted as a G++
2645+
extension). If the array member has been initialized,
2646+
determine its size from the initializer. Otherwise,
2647+
the array size is zero. */
2648+
if (tree init = find_field_init (oper, DECL_INITIAL (var_decl)))
2649+
bytes_avail = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (init)));
2650+
}
2651+
else
2652+
bytes_avail = (wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node))
2653+
- compsize);
26422654
}
26432655

2644-
tree_code oper_code = TREE_CODE (TREE_TYPE (oper));
2656+
tree_code oper_code = TREE_CODE (opertype);
26452657

26462658
if (compref && oper_code == ARRAY_TYPE)
26472659
{
2648-
/* Avoid diagnosing flexible array members (which are accepted
2649-
as an extension and diagnosed with -Wpedantic) and zero-length
2650-
arrays (also an extension).
2651-
Overflowing construction in one-element arrays is diagnosed
2652-
only at level 2. */
2653-
if (bytes_avail == 0 && !var_decl)
2654-
return;
2655-
2656-
tree nelts = array_type_nelts_top (TREE_TYPE (oper));
2660+
tree nelts = array_type_nelts_top (opertype);
26572661
tree nelts_cst = maybe_constant_value (nelts);
26582662
if (TREE_CODE (nelts_cst) == INTEGER_CST
26592663
&& integer_onep (nelts_cst)
@@ -2662,29 +2666,35 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
26622666
return;
26632667
}
26642668

2665-
/* The size of the buffer can only be adjusted down but not up. */
2666-
gcc_checking_assert (0 <= adjust);
2667-
26682669
/* Reduce the size of the buffer by the adjustment computed above
26692670
from the offset and/or the index into the array. */
2670-
if (bytes_avail < static_cast<unsigned HOST_WIDE_INT>(adjust))
2671+
if (bytes_avail < adjust || adjust < 0)
26712672
bytes_avail = 0;
26722673
else
2673-
bytes_avail -= adjust;
2674+
{
2675+
tree elttype = (TREE_CODE (opertype) == ARRAY_TYPE
2676+
? TREE_TYPE (opertype) : opertype);
2677+
if (tree eltsize = TYPE_SIZE_UNIT (elttype))
2678+
{
2679+
bytes_avail -= adjust * wi::to_offset (eltsize);
2680+
if (bytes_avail < 0)
2681+
bytes_avail = 0;
2682+
}
2683+
}
26742684

26752685
/* The minimum amount of space needed for the allocation. This
26762686
is an optimistic estimate that makes it possible to detect
26772687
placement new invocation for some undersize buffers but not
26782688
others. */
2679-
unsigned HOST_WIDE_INT bytes_need;
2689+
offset_int bytes_need;
26802690

26812691
if (CONSTANT_CLASS_P (size))
2682-
bytes_need = tree_to_uhwi (size);
2692+
bytes_need = wi::to_offset (size);
26832693
else if (nelts && CONSTANT_CLASS_P (nelts))
2684-
bytes_need = tree_to_uhwi (nelts)
2685-
* tree_to_uhwi (TYPE_SIZE_UNIT (type));
2694+
bytes_need = (wi::to_offset (nelts)
2695+
* wi::to_offset (TYPE_SIZE_UNIT (type)));
26862696
else if (tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
2687-
bytes_need = tree_to_uhwi (TYPE_SIZE_UNIT (type));
2697+
bytes_need = wi::to_offset (TYPE_SIZE_UNIT (type));
26882698
else
26892699
{
26902700
/* The type is a VLA. */
@@ -2703,9 +2713,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
27032713
: "placement new constructing an object of type "
27042714
"%<%T [%wu]%> and size %qwu in a region of type %qT "
27052715
"and size at most %qwu",
2706-
type, tree_to_uhwi (nelts), bytes_need,
2707-
TREE_TYPE (oper),
2708-
bytes_avail);
2716+
type, tree_to_uhwi (nelts), bytes_need.to_uhwi (),
2717+
opertype, bytes_avail.to_uhwi ());
27092718
else
27102719
warning_at (loc, OPT_Wplacement_new_,
27112720
exact_size ?
@@ -2715,8 +2724,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
27152724
: "placement new constructing an array of objects "
27162725
"of type %qT and size %qwu in a region of type %qT "
27172726
"and size at most %qwu",
2718-
type, bytes_need, TREE_TYPE (oper),
2719-
bytes_avail);
2727+
type, bytes_need.to_uhwi (), opertype,
2728+
bytes_avail.to_uhwi ());
27202729
else
27212730
warning_at (loc, OPT_Wplacement_new_,
27222731
exact_size ?
@@ -2725,8 +2734,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
27252734
: "placement new constructing an object of type %qT "
27262735
"and size %qwu in a region of type %qT and size "
27272736
"at most %qwu",
2728-
type, bytes_need, TREE_TYPE (oper),
2729-
bytes_avail);
2737+
type, bytes_need.to_uhwi (), opertype,
2738+
bytes_avail.to_uhwi ());
27302739
}
27312740
}
27322741
}

gcc/testsuite/ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
2017-11-27 Martin Sebor <[email protected]>
2+
3+
PR c++/83058
4+
* g++.dg/warn/Wplacement-new-size-5.C: New test.
5+
16
2017-11-27 Jakub Jelinek <[email protected]>
27

38
PR c++/81888

0 commit comments

Comments
 (0)