PR c++/67942 - diagnose placement new buffer overflow

gcc/
        * invoke.texi (-Wplacement-new): Document new option.
	* gcc/testsuite/g++.dg/warn/Wplacement-new-size.C: New test.

gcc/c-family/
        * c.opt (-Wplacement-new): New option.

gcc/cp/
	* cp/init.c (warn_placement_new_too_small): New function.
	(build_new_1): Call it.

gcc/testsuite/
        * g++.dg/warn/Wplacement-new-size.C: New test.

From-SVN: r229827
This commit is contained in:
Martin Sebor 2015-11-05 21:42:10 +00:00 committed by Martin Sebor
parent 60f2d2f36d
commit e2f5cc96e5
8 changed files with 660 additions and 8 deletions

View file

@ -1,3 +1,9 @@
2015-11-05 Martin Sebor <msebor@redhat.com>
PR c++/67942
* invoke.texi (-Wplacement-new): Document new option.
* gcc/testsuite/g++.dg/warn/Wplacement-new-size.C: New test.
2015-11-05 Alan Lawrence <alan.lawrence@arm.com>
PR tree-optimization/65963

View file

@ -1,3 +1,8 @@
2015-11-05 Martin Sebor <msebor@redhat.com>
PR c++/67942
* c.opt (-Wplacement-new): New option.
2015-11-05 Jakub Jelinek <jakub@redhat.com>
* c-common.h (c_finish_omp_atomic): Add TEST argument.

View file

@ -776,6 +776,10 @@ Wprotocol
ObjC ObjC++ Var(warn_protocol) Init(1) Warning
Warn if inherited methods are unimplemented.
Wplacement-new
C++ Var(warn_placement_new) Init(1) Warning
Warn for placement new expressions with undefined behavior
Wredundant-decls
C ObjC C++ ObjC++ Var(warn_redundant_decls) Warning
Warn about multiple declarations of the same object.

View file

@ -1,3 +1,9 @@
2015-11-05 Martin Sebor <msebor@redhat.com>
PR c++/67942
* cp/init.c (warn_placement_new_too_small): New function.
(build_new_1): Call it.
2015-11-05 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/67846

View file

@ -2276,6 +2276,201 @@ throw_bad_array_new_length (void)
return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
}
/* 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
it does not. SIZE specifies the size needed to construct the object or
array and captures the result of NELTS * sizeof (TYPE). (SIZE could be
greater when the array under construction requires a cookie to store
NELTS. GCC's placement new expression stores the cookie when invoking
a user-defined placement new operator function but not the default one.
Placement new expressions with user-defined placement new operator are
not diagnosed since we don't know how they use the buffer (this could
be a future extension). */
static void
warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
{
location_t loc = EXPR_LOC_OR_LOC (oper, input_location);
/* 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) the final
result cannot be. */
HOST_WIDE_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
to placement new is not checked since it's unknown what it might
point to. */
if (TREE_CODE (oper) == PARM_DECL
|| TREE_CODE (oper) == VAR_DECL
|| TREE_CODE (oper) == COMPONENT_REF)
return;
/* 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 comple-time constant, use it to compute a more
accurate estimate of the size of the buffer. Otherwise, use
the size of the entire array as an optimistic estimate (this
may lead to false negatives). */
const_tree adj = TREE_OPERAND (oper, 1);
if (CONSTANT_CLASS_P (adj))
adjust += tree_to_uhwi (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)
{
/* 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 = TREE_OPERAND (oper, 1);
if (!use_obj_size && CONSTANT_CLASS_P (adj))
adjust += tree_to_shwi (adj);
else
{
use_obj_size = true;
adjust = 0;
}
oper = TREE_OPERAND (oper, 0);
}
/* Descend into a struct or union to find the member whose address
is being used as the agument. */
while (TREE_CODE (oper) == COMPONENT_REF)
oper = TREE_OPERAND (oper, 1);
if ((addr_expr || !POINTER_TYPE_P (TREE_TYPE (oper)))
&& (TREE_CODE (oper) == VAR_DECL
|| TREE_CODE (oper) == FIELD_DECL
|| TREE_CODE (oper) == PARM_DECL))
{
/* A possibly optimistic estimate of the number of bytes available
in the destination buffer. */
unsigned HOST_WIDE_INT bytes_avail;
/* 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 (TREE_CODE (oper) == VAR_DECL || use_obj_size)
{
/* 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 = tree_to_shwi (DECL_SIZE_UNIT (oper));
exact_size = !use_obj_size;
}
else
{
/* Use the size of the type of the destination buffer object
as the optimistic estimate of the available space in it. */
bytes_avail = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (oper)));
}
/* Avoid diagnosing flexible array members (accepted as an extension
and diagnosed with -Wpedantic).
Constructing objects that appear to overflow the C99 equivalent of
flexible array members (i.e., array members of size zero or one)
are diagnosed in C++ since their declaration cannot be diagnosed. */
if (bytes_avail == 0 && TREE_CODE (TREE_TYPE (oper)) == ARRAY_TYPE)
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
from the offset and/or the index into the array. */
if (bytes_avail < static_cast<unsigned HOST_WIDE_INT>(adjust))
bytes_avail = 0;
else
bytes_avail -= adjust;
/* 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. */
unsigned HOST_WIDE_INT bytes_need;
if (CONSTANT_CLASS_P (size))
bytes_need = tree_to_uhwi (size);
else if (nelts && CONSTANT_CLASS_P (nelts))
bytes_need = tree_to_uhwi (nelts)
* tree_to_uhwi (TYPE_SIZE_UNIT (type));
else
bytes_need = tree_to_uhwi (TYPE_SIZE_UNIT (type));
if (bytes_avail < bytes_need)
{
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 [%lu]%> and size %qwu in a region of type %qT "
"and size at most %qwu",
type, tree_to_uhwi (nelts), bytes_need,
TREE_TYPE (oper),
bytes_avail);
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",
type, bytes_need, TREE_TYPE (oper),
bytes_avail);
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",
type, bytes_need, TREE_TYPE (oper),
bytes_avail);
}
}
}
/* Generate code for a new-expression, including calling the "operator
new" function, initializing the object, and, if an exception occurs
during construction, cleaning up. The arguments are as for
@ -2525,6 +2720,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
&& (TYPE_PTR_P (TREE_TYPE ((**placement)[0]))))
placement_first = (**placement)[0];
bool member_new_p = false;
/* Allocate the object. */
if (vec_safe_is_empty (*placement) && TYPE_FOR_JAVA (elt_type))
{
@ -2573,11 +2770,13 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
fnname = ansi_opname (array_p ? VEC_NEW_EXPR : NEW_EXPR);
if (!globally_qualified_p
member_new_p = !globally_qualified_p
&& CLASS_TYPE_P (elt_type)
&& (array_p
? TYPE_HAS_ARRAY_NEW_OPERATOR (elt_type)
: TYPE_HAS_NEW_OPERATOR (elt_type)))
: TYPE_HAS_NEW_OPERATOR (elt_type));
if (member_new_p)
{
/* Use a class-specific operator new. */
/* If a cookie is required, add some extra space. */
@ -2652,20 +2851,30 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
/* If we found a simple case of PLACEMENT_EXPR above, then copy it
into a temporary variable. */
if (!processing_template_decl
&& placement_first != NULL_TREE
&& TREE_CODE (alloc_call) == CALL_EXPR
&& call_expr_nargs (alloc_call) == 2
&& TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 0))) == INTEGER_TYPE
&& TYPE_PTR_P (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 1))))
{
tree placement_arg = CALL_EXPR_ARG (alloc_call, 1);
tree placement = CALL_EXPR_ARG (alloc_call, 1);
if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg)))
|| VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg))))
if (placement_first != NULL_TREE
&& (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (TREE_TYPE (placement)))
|| VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement)))))
{
placement_expr = get_target_expr (placement_first);
CALL_EXPR_ARG (alloc_call, 1)
= convert (TREE_TYPE (placement_arg), placement_expr);
= convert (TREE_TYPE (placement), placement_expr);
}
if (!member_new_p
&& VOID_TYPE_P (TREE_TYPE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 1)))))
{
/* Attempt to make the warning point at the operator new argument. */
if (placement_first)
placement = placement_first;
warn_placement_new_too_small (orig_type, nelts, size, placement);
}
}

View file

@ -272,7 +272,7 @@ Objective-C and Objective-C++ Dialects}.
-Woverride-init-side-effects @gol
-Woverlength-strings -Wpacked -Wpacked-bitfield-compat -Wpadded @gol
-Wparentheses -Wpedantic-ms-format -Wno-pedantic-ms-format @gol
-Wpointer-arith -Wno-pointer-to-int-cast @gol
-Wplacement-new -Wpointer-arith -Wno-pointer-to-int-cast @gol
-Wredundant-decls -Wno-return-local-addr @gol
-Wreturn-type -Wsequence-point -Wshadow -Wno-shadow-ivar @gol
-Wshift-overflow -Wshift-overflow=@var{n} @gol
@ -4870,6 +4870,13 @@ disables the warnings about non-ISO @code{printf} / @code{scanf} format
width specifiers @code{I32}, @code{I64}, and @code{I} used on Windows targets,
which depend on the MS runtime.
@item -Wplacement-new
@opindex Wplacement-new
@opindex Wno-placement-new
Warn about placement new expressions with undefined behavior, such as
constructing an object in a buffer that is smaller than the type of
the object.
@item -Wpointer-arith
@opindex Wpointer-arith
@opindex Wno-pointer-arith

View file

@ -1,3 +1,8 @@
2015-11-05 Martin Sebor <msebor@redhat.com>
PR c++/67942
* g++.dg/warn/Wplacement-new-size.C: New test.
2015-11-05 Alan Lawrence <alan.lawrence@arm.com>
* gcc.dg/pr68112.c: New.

View file

@ -0,0 +1,410 @@
/* { dg-do compile } */
/* { dg-options "-Wplacement-new -fpermissive" } */
typedef __typeof__ (sizeof 0) size_t;
void* operator new (size_t, void *p) { return p; }
void* operator new[] (size_t, void *p) { return p; }
static __attribute__ ((used))char c;
static __attribute__ ((used))char ac1 [1];
static __attribute__ ((used))char ac2 [2];
static __attribute__ ((used))char ac3 [3];
static __attribute__ ((used))char ac4 [4];
static __attribute__ ((used))char ac5 [5];
static __attribute__ ((used))char ac6 [6];
static __attribute__ ((used))char ac7 [7];
static __attribute__ ((used))char ac8 [8];
static __attribute__ ((used))char ac1_1 [1][1];
static __attribute__ ((used))char ac1_2 [1][2];
static __attribute__ ((used))char ac2_1 [2][1];
static __attribute__ ((used))char ac2_2 [2][2];
static __attribute__ ((used))short s;
static __attribute__ ((used))short as1 [1];
static __attribute__ ((used))short as2 [2];
static __attribute__ ((used))struct SC { char c; char *pc; void *pv; } sc;
static __attribute__ ((used))struct SAC1 { char ac [1]; } sac1;
static __attribute__ ((used))struct SAC2 { char ac [2]; } sac2;
static __attribute__ ((used))struct SAC3 { char ac [3]; } sac3;
static __attribute__ ((used))struct SAC4 { char ac [4]; } sac4;
static __attribute__ ((used))struct SSC { SC sc; int x; } ssc;
static __attribute__ ((used))struct SSAC1 { SAC1 sac; } ssac1;
static __attribute__ ((used))struct SSAC2 { SAC2 sac; } ssac2;
static __attribute__ ((used))struct SSAC3 { SAC3 sac; } ssac3;
static __attribute__ ((used))struct SSAC4 { SAC4 sac; } ssac4;
static __attribute__ ((used))struct SSAC4_2 { SSAC4 ssac4_2 [2]; } sssac4_2;
static __attribute__ ((used))union UAC1 { char c; char ac [1]; } uac1;
static __attribute__ ((used))union UAC2 { char c; char ac [2]; } uac2;
static __attribute__ ((used))union UAC3 { char c; char ac [3]; } uac3;
static __attribute__ ((used))union UAC4 { char c; char ac [4]; } uac4;
static __attribute__ ((used))SC fsc () { return SC (); }
static __attribute__ ((used))SAC1 fasc1 () { return SAC1 (); }
static __attribute__ ((used))SAC2 fasc2 () { return SAC2 (); }
static __attribute__ ((used))SAC3 fasc3 () { return SAC3 (); }
static __attribute__ ((used))SAC4 fasc4 () { return SAC4 (); }
static __attribute__ ((used))void *r;
static __attribute__ ((used))void* ptr () { return 0; }
static __attribute__ ((used))
void test (void *p, int n)
{
{
void *q = p;
struct { void *p; } s = { p };
// Verify that none of function arguments, local or global
// variables, or function return values trigger the warning.
new (p) char;
new (q) char;
new (r) char;
new (s.p) char;
new (ptr ()) char;
new (p) char [32];
new (q) char [32];
new (r) char [32];
new (s.p) char [32];
new (ptr ()) char [32];
new (&p) char;
new (&q) char;
new (&r) char;
// Using address of objects, however, must trigger the warning.
new (&p) char [32]; // { dg-warning "placement" }
new (&q) char [32]; // { dg-warning "placement" }
new (&r) char [32]; // { dg-warning "placement" }
}
enum { N0, N1, N2, N3 };
new (&c) char;
// Warn for the common case when constructing at an offset from
// the beginning of an array that doesn't leave enough space for
// the object.
new (&c + 0) char; // okay
new (&c + n) char; // okay (n is unknown)
new (&c + 1) char; // { dg-warning "placement" }
new (&c + N0) char;
new (&c + N1) char; // { dg-warning "placement" }
// No warning is issued when constructing an array in space exactly
// its size even though strictly speaking a compiler is allowed to
// add a cookie to the array (gcc does not).
new (&c) char [1];
new (&c) char [sizeof c];
new (&c) char [n];
new (&c) char [1][1];
new (&c) char [1][1][1];
new (&c + N1) char [1][1][1]; // { dg-warning "placement" }
new (&c) char [2]; // { dg-warning "placement" }
new (&c) char [sizeof c + 1]; // { dg-warning "placement" }
new (&c) char [1][2]; // { dg-warning "placement" }
new (&c) char [2][1]; // { dg-warning "placement" }
new (&c) char [n][1];
new (&c) char [n][2]; // { dg-warning "placement" }
new (&c) char [3]; // { dg-warning "placement" }
new (&c) char [3][1]; // { dg-warning "placement" }
new (&c) char [1][3]; // { dg-warning "placement" }
new (&c) char [4][1]; // { dg-warning "placement" }
new (&c) char [1][4]; // { dg-warning "placement" }
// Casts must not suppress it.
new ((void*)&c) char [2]; // { dg-warning "placement" }
new ((char*)&c) char [3]; // { dg-warning "placement" }
new (static_cast<void*>(&c)) char [4]; // { dg-warning "placement" }
new (reinterpret_cast<char*>(&c)) char [5]; // { dg-warning "placement" }
new (&c + 0) char [2]; // { dg-warning "placement" }
new (&c + 0) char [3]; // { dg-warning "placement" }
new (&c + 0) char [4]; // { dg-warning "placement" }
new (&c + 1) char [2]; // { dg-warning "placement" }
new (&c + 1) char [3]; // { dg-warning "placement" }
new (&c + 1) char [4]; // { dg-warning "placement" }
new (&c + N0) char [1];
new (&c + N1) char [2]; // { dg-warning "placement" }
// Warn even though n is unknown since c is too small for char[2]
// regardless of the value of n.
new (&c + n) char [2]; // { dg-warning "placement" }
new (ac2) char [1];
new (ac2) char [1][1];
new (ac2) char [1][2];
new (ac2) char [2][1];
new (ac2) char [1][3]; // { dg-warning "placement" }
new (ac2) char [2][2]; // { dg-warning "placement" }
new (ac2) char [3][1]; // { dg-warning "placement" }
new (ac2 + N0) char [1][1];
new (ac2 + N0) char [1][2];
new (ac2 + N1) char [1][2]; // { dg-warning "placement" }
new (ac2 + N1) char [2][1]; // { dg-warning "placement" }
new (ac2 + N2) char [1][1]; // { dg-warning "placement" }
new (ac2 + N2) char [1][2]; // { dg-warning "placement" }
new (ac2 + N2) char [2][1]; // { dg-warning "placement" }
new (ac2 + N2) char [2][2]; // { dg-warning "placement" }
new (ac8) char [1];
new (ac8) char [2][2];
new (ac8) char [2][3];
new (ac8) char [2][4];
new (ac8) char [2][5]; // { dg-warning "placement" }
new (ac8) char [2][2][2];
new (ac8) char [2][2][3]; // { dg-warning "placement" }
new (&c) int; // { dg-warning "placement" }
new (&ac1) int; // { dg-warning "placement" }
new (&ac2) int; // { dg-warning "placement" }
new (&ac3) int; // { dg-warning "placement" }
new (&ac4) int;
// Constructing at an address of an array element.
new (&ac1 [0]) int; // { dg-warning "placement" }
new (&ac2 [0]) int; // { dg-warning "placement" }
new (&ac3 [0]) int; // { dg-warning "placement" }
new (&ac4 [0]) int;
// ...plus or minus a constant offset.
new (&ac1 [0] + 0) int; // { dg-warning "placement" }
new (&ac2 [0] + 0) int; // { dg-warning "placement" }
new (&ac3 [0] + 0) int; // { dg-warning "placement" }
new (&ac4 [0] + 0) int;
new (&ac4 [1] + 0) int; // { dg-warning "placement" }
new (&ac4 [1] - 1) int;
new (&ac4 [2] - 1) int; // { dg-warning "placement" }
new (&ac4 [2] - 2) int;
new (&ac4 [3] - 1) int; // { dg-warning "placement" }
new (&ac4 [3] - 2) int; // { dg-warning "placement" }
new (&ac4 [3] - 3) int;
new (&ac4 [4] - 1) int; // { dg-warning "placement" }
new (&ac4 [4] - 2) int; // { dg-warning "placement" }
new (&ac4 [4] - 3) int; // { dg-warning "placement" }
new (&ac4 [4] - 4) int;
new (&ac1 [0] + 1) int; // { dg-warning "placement" }
new (&ac2 [0] + 1) int; // { dg-warning "placement" }
new (&ac3 [0] + 1) int; // { dg-warning "placement" }
new (&ac4 [0] + 1) int; // { dg-warning "placement" }
new (&ac3 [0] + n) int; // { dg-warning "placement" }
new (&ac4 [0] + n) int; // no warning (n could be zero)
new (&ac4 [1] + n) int; // no warning (n could be negative)
new (&ac4 [2] + n) int; // ditto
new (&ac4 [3] + n) int; // ditto
new (&ac4 [4] + n) int; // ditto
new (&ac4 [4] - n) int; // (or positive)
new (&c + 0) int; // { dg-warning "placement" }
new (&c + 1) int; // { dg-warning "placement" }
// Constructing at an offset into the address of an array.
new (&ac1 + 0) int; // { dg-warning "placement" }
new (&ac1 + 1) int; // { dg-warning "placement" }
new (&ac1 + n) int; // { dg-warning "placement" }
new (&ac2 + 0) int; // { dg-warning "placement" }
new (&ac2 + 1) int; // { dg-warning "placement" }
new (&ac2 + n) int; // { dg-warning "placement" }
new (&ac3 + 0) int; // { dg-warning "placement" }
new (&ac3 + 1) int; // { dg-warning "placement" }
// Even though n below is uknown an array of 3 bytes isn't large
// enugh for an int.
new (&ac3 + n) int; // { dg-warning "placement" }
new (&ac4 + 0) int;
new (&ac4 + 1) int; // { dg-warning "placement" }
new (&ac4 + n) int; // no warning (n could be zero)
// Constructing in an array object.
new (ac1) int; // { dg-warning "placement" }
new (ac2) int; // { dg-warning "placement" }
new (ac3) int; // { dg-warning "placement" }
new (ac4) int;
new (ac5) int;
new (ac5 + 0) int;
new (ac5 + 1) int;
new (ac5 + n) int; // no warning (n could be zero)
new (ac5 + 2) int; // { dg-warning "placement" }
new (ac5 + 3) int; // { dg-warning "placement" }
new (ac5 + 4) int; // { dg-warning "placement" }
new (ac5 + 5) int; // { dg-warning "placement" }
new (ac1_1) char;
new (ac1_1) char[1];
new (ac1_1) char[n]; // no warning (n is unknown)
new (ac1_1) char[2]; // { dg-warning "placement" }
new (ac1_1) char[3]; // { dg-warning "placement" }
new (ac1_2) char;
new (ac1_2) char[1];
new (ac1_2) char[2];
new (ac1_2) char[3]; // { dg-warning "placement" }
new (ac2_1) char;
new (ac2_1) char[1];
new (ac2_1) char[2];
new (ac2_1) char[3]; // { dg-warning "placement" }
new (ac2_2) char;
new (ac2_2) char[1];
new (ac2_2) char[2];
new (ac2_2) char[2][2];
// Even though n below is uknown it can't meaningfully be zero
// (even if zero-size arrays are allowed as an extension, the size
// they are allocated in by placement new is zero).
new (ac1_1) char[n][2]; // { dg-warning "placement" }
new (ac2_2) char[3];
new (ac2_2) char[3][1];
new (ac2_2) char[3][2]; // { dg-warning "placement" }
new (ac2_2) char[4];
new (ac2_2) char[4][1];
new (ac2_2) char[4][2]; // { dg-warning "placement" }
new (ac2_2) char[5]; // { dg-warning "placement" }
new (&s) int; // { dg-warning "placement" }
new (&as1) int; // { dg-warning "placement" }
new (&as2) int;
new (as1) int; // { dg-warning "placement" }
new (as2) int;
new (&sc.c) int; // { dg-warning "placement" }
new (&sac1.ac) int; // { dg-warning "placement" }
new (&sac2.ac) int; // { dg-warning "placement" }
new (&sac3.ac) int; // { dg-warning "placement" }
new (&sac4.ac) int;
new (sc.pc) char;
new (sc.pc) int;
new (sc.pc) int[1024];
new (sc.pc + 0) int;
new (sc.pc + 0) int[2048];
new (sc.pv) int;
new (sc.pv) char[1024];
new (sac1.ac) int; // { dg-warning "placement" }
new (sac2.ac) int; // { dg-warning "placement" }
new (sac3.ac) int; // { dg-warning "placement" }
new (sac4.ac) int;
new (&ssc.sc) SSC; // { dg-warning "placement" }
new (&ssac1.sac) int; // { dg-warning "placement" }
new (&ssac2.sac) int; // { dg-warning "placement" }
new (&ssac3.sac) int; // { dg-warning "placement" }
new (&ssac4.sac) int;
new (&sssac4_2) char[sizeof sssac4_2];
new (&sssac4_2) char[sizeof sssac4_2 + 1]; // { dg-warning "placement" }
// taking the address of a temporary is allowed with -fpermissive
new (&fsc ().c) int; // { dg-warning "address|placement" }
new (&fasc1 ().ac) int; // { dg-warning "address|placement" }
new (&fasc2 ().ac) int; // { dg-warning "address|placement" }
new (&fasc3 ().ac) int; // { dg-warning "address|placement" }
new (&fasc4 ().ac) int; // { dg-warning "address|placement" }
new (&uac1) int; // { dg-warning "placement" }
new (&uac2) int; // { dg-warning "placement" }
new (&uac3) int; // { dg-warning "placement" }
new (&uac4) int;
new (&uac4 + 1) int; // { dg-warning "placement" }
new (&uac1.c) int; // { dg-warning "placement" }
new (&uac2.c) int; // { dg-warning "placement" }
new (&uac3.c) int; // { dg-warning "placement" }
// Diagnose the following even though the size of uac4.c could be
// expected to extend to the end of the union (as it is by Built-in
// Object Size and so isn't diagnosed in calls to functions like
// memset(&uac4.c, 0, sizeof(int)) when _FORTIFY_SOURCE is non-zero. */
new (&uac4.c) int; // { dg-warning "placement" }
new (&uac4.c + 1) int; // { dg-warning "placement" }
}
struct S { char c [2]; };
// Verify the full text of the warning message.
static __attribute__ ((used))
void test_message (int i)
{
char a [2];
// The exact sizes of both the buffer and the type are known.
new (a + 1) S; // { dg-warning "placement new constructing an object of type .S. and size .2. in a region of type .char \\\[2\\\]. and size .1." }
// The buffer size is known but only the size of the type whose
// objects are being constructed is known, not their number. While
// in theory it could be zero, it practice likely never will be so
// the potential false positive is acceptable.
new (a + 1) S [i]; // { dg-warning "placement new constructing an array of objects of type .S. and size .2. in a region of type .char \\\[2\\\]. and size .1." }
// The exact amount of space in the buffer isn't known, only its
// maximum is. The exact size of the array being created is known.
new (a + i) S [2]; // { dg-warning "placement new constructing an object of type .S \\\[2\\\]. and size .4. in a region of type .char \\\[2\\\]. and size at most .2." }
}
struct ClassWithMemberNew {
struct Object { int i; } *pobj;
unsigned nobj;
ClassWithMemberNew ();
void foo ();
void* operator new (size_t, void*);
void* operator new[] (size_t, void*);
};
void ClassWithMemberNew::foo()
{
for (unsigned i = 0; i != nobj; ++i)
new (pobj + i) Object ();
}
struct ClassWithGlobalNew {
int a [4];
ClassWithGlobalNew ();
};
void* operator new (size_t, ClassWithGlobalNew*);
void* operator new[] (size_t, ClassWithGlobalNew*);
void test_user_defined_placement_new ()
{
{
ClassWithMemberNew x;
// Expect no diagnostics for placement new expressions with types
// with their own placement operator new since the semantics of
// the operator aren't known.
new (&c) ClassWithMemberNew;
new (&x) ClassWithMemberNew[2];
}
{
ClassWithGlobalNew x;
new (&c) ClassWithGlobalNew; // { dg-warning "placement" }
new (&x) ClassWithGlobalNew[2];
}
}