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:
parent
60f2d2f36d
commit
e2f5cc96e5
8 changed files with 660 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
223
gcc/cp/init.c
223
gcc/cp/init.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
410
gcc/testsuite/g++.dg/warn/Wplacement-new-size.C
Normal file
410
gcc/testsuite/g++.dg/warn/Wplacement-new-size.C
Normal 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];
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue