gcc/cp/ChangeLog 2015-10-19 Martin Sebor PR c++/67913 PR c++/67927 * call.c (build_operator_new_call): Do not assume size_check is non-null, analogously to the top half of the function. * init.c (build_new_1): Detect and diagnose array sizes in excess of the maximum of roughly SIZE_MAX / 2. Insert a runtime check only for arrays with a non-constant size. (build_new): Detect and diagnose negative array sizes. gcc/testsuite/ChangeLog 2015-10-19 Martin Sebor * init/new45.C: New test to verify that operator new is invoked with or without overhead for a cookie. PR c++/67927 * init/new44.C: New test for placement new expressions for arrays with excessive number of elements. PR c++/67913 * init/new43.C: New test for placement new expressions for arrays with negative number of elements. * other/new-size-type.C: Expect array new expression with an excessive number of elements to be rejected. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 367d42b..3f76198 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4228,10 +4228,12 @@ build_operator_new_call (tree fnname, vec **args, { /* Update the total size. */ *size = size_binop (PLUS_EXPR, original_size, *cookie_size); + if (size_check) + { /* Set to (size_t)-1 if the size check fails. */ - gcc_assert (size_check != NULL_TREE); *size = fold_build3 (COND_EXPR, sizetype, size_check, *size, TYPE_MAX_VALUE (sizetype)); + } /* Update the argument list to reflect the adjusted size. */ (**args)[0] = *size; } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1ed8f6c..3b88098 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2272,7 +2272,11 @@ throw_bad_array_new_length (void) /* 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 - build_raw_new_expr. This may change PLACEMENT and INIT. */ + build_raw_new_expr. This may change PLACEMENT and INIT. + TYPE is the type of the object being constructed, possibly an array + of NELTS elements when NELTS is non-null (in "new T[NELTS]", T may + be an array of the form U[inner], with the whole expression being + "new U[NELTS][inner]"). */ static tree build_new_1 (vec **placement, tree type, tree nelts, @@ -2292,13 +2296,16 @@ build_new_1 (vec **placement, tree type, tree nelts, type.) */ tree pointer_type; tree non_const_pointer_type; + /* The most significant array bound in int[OUTER_NELTS][inner]. */ tree outer_nelts = NULL_TREE; - /* For arrays, a bounds checks on the NELTS parameter. */ + /* For arrays with a non-constant number of elements, a bounds checks + on the NELTS parameter to avoid integer overflow at runtime. */ tree outer_nelts_check = NULL_TREE; bool outer_nelts_from_type = false; + /* Number of the "inner" elements in "new T[OUTER_NELTS][inner]". */ offset_int inner_nelts_count = 1; tree alloc_call, alloc_expr; - /* Size of the inner array elements. */ + /* Size of the inner array elements (those with constant dimensions). */ offset_int inner_size; /* The address returned by the call to "operator new". This node is a VAR_DECL and is therefore reusable. */ @@ -2492,21 +2499,41 @@ build_new_1 (vec **placement, tree type, tree nelts, } max_outer_nelts = wi::udiv_trunc (max_size, inner_size); - /* Only keep the top-most seven bits, to simplify encoding the - constant in the instruction stream. */ + max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts); + + size = size_binop (MULT_EXPR, size, convert (sizetype, nelts)); + + if (TREE_CONSTANT (outer_nelts)) + { + if (tree_int_cst_lt (max_outer_nelts_tree, outer_nelts)) + { + /* When the array size is constant, check it at compile time + to make sure it doesn't exceed the implementation-defined + maximum, as required by C++ 14 (in C++ 11 this requirement + isn't explicitly stated but it's enforced anyway -- see + grokdeclarator in cp/decl.c). */ + if (complain & tf_error) + error ("size of array is too large"); + return error_mark_node; + } + } + else { + /* When a runtime check is necessary because the array size + isn't constant, keep only the top-most seven bits (starting + with the most significant non-zero bit) of the maximum size + to compare the array size against, to simplify encoding the + constant maximum size in the instruction stream. */ unsigned shift = (max_outer_nelts.get_precision ()) - 7 - wi::clz (max_outer_nelts); max_outer_nelts = wi::lshift (wi::lrshift (max_outer_nelts, shift), shift); - } - max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts); - size = size_binop (MULT_EXPR, size, convert (sizetype, nelts)); outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node, outer_nelts, max_outer_nelts_tree); } + } alloc_fn = NULL_TREE; @@ -3066,6 +3093,23 @@ build_new (vec **placement, tree type, tree nelts, else return error_mark_node; } + + /* Try to determine the constant value only for the purposes + of the diagnostic below but continue to use the original + value and handle const folding later. */ + const_tree cst_nelts = maybe_constant_value (nelts); + + /* The expression in a noptr-new-declarator is erroneous if it's of + non-class type and its value before converting to std::size_t is + less than zero. ... If the expression is a constant expression, + the program is ill-fomed. */ + if (TREE_CONSTANT (cst_nelts) && tree_int_cst_sgn (cst_nelts) == -1) + { + if (complain & tf_error) + error ("size of array is negative"); + return error_mark_node; + } + nelts = mark_rvalue_use (nelts); nelts = cp_save_expr (cp_convert (sizetype, nelts, complain)); } diff --git a/gcc/testsuite/g++.dg/init/new43.C b/gcc/testsuite/g++.dg/init/new43.C new file mode 100644 index 0000000..9b08667 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/new43.C @@ -0,0 +1,164 @@ +/* { dg-do compile } */ + +// Test for PR c++/67913 - new expression with negative size not diagnosed. +typedef __typeof__ (sizeof 0) size_t; + +void* operator new (size_t, void*); +void* operator new[] (size_t, void*); + +struct A { + int a [4]; +}; + +struct B { + int a [4]; + + void* operator new (size_t, void*); + void* operator new[] (size_t, void*); +}; + +void* operator new (size_t, B*); +void* operator new[] (size_t, B*); + +void *p; + +void test_literal () +{ + char c; + (void)c; + + B b; + + // Verify integer literal. + p = new char [-1]; // { dg-error "size of array is negative" } + p = new char [2][-3]; // { dg-error "size of array is negative" } + p = new char [-4][5]; // { dg-error "size of array is negative" } + p = new char [-6][-7]; // { dg-error "size of array is negative" } + + p = new (p) char [-1]; // { dg-error "size of array is negative" } + p = new (p) char [2][-3]; // { dg-error "size of array is negative" } + p = new (p) char [-4][5]; // { dg-error "size of array is negative" } + p = new (p) char [-6][-7]; // { dg-error "size of array is negative" } + + p = new (p) A [-1]; // { dg-error "size of array is negative" } + p = new (p) A [2][-3]; // { dg-error "size of array is negative" } + p = new (p) A [-4][5]; // { dg-error "size of array is negative" } + p = new (p) A [-6][-7]; // { dg-error "size of array is negative" } + + p = new (p) B [-1]; // { dg-error "size of array is negative" } + p = new (p) B [2][-3]; // { dg-error "size of array is negative" } + p = new (p) B [-4][5]; // { dg-error "size of array is negative" } + p = new (p) B [-6][-7]; // { dg-error "size of array is negative" } + + p = new (&b) B [-1]; // { dg-error "size of array is negative" } + p = new (&b) B [2][-3]; // { dg-error "size of array is negative" } + p = new (&b) B [-4][5]; // { dg-error "size of array is negative" } + p = new (&b) B [-6][-7]; // { dg-error "size of array is negative" } + + p = new char [1 - 2]; // { dg-error "size of array is negative" } + p = new (p) char [2 - 3]; // { dg-error "size of array is negative" } + p = new A [2 < 1 ? -1 : -2]; // { dg-error "size of array is negative" } + p = new (p) B [2 - 3 * 2]; // { dg-error "size of array is negative" } + p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is negative" } +} + +void test_constant_expression () +{ + char c; + (void)c; + + B b; + + static const signed char i1 = -1; + static const signed short i2 = -2; + static const signed int i3 = -3; + static const signed long i4 = -4; + static const signed long long i5 = -5; + static const int i6 = -6; + static const int i7 = -7; + + // Verify constant expression. + p = new char [i1]; // { dg-error "size of array is negative" } + p = new char [2][i3]; // { dg-error "size of array is negative" } + p = new char [i4][5]; // { dg-error "size of array is negative" } + p = new char [i6][i7]; // { dg-error "size of array is negative" } + + p = new (p) char [i1]; // { dg-error "size of array is negative" } + p = new (p) char [2][i3]; // { dg-error "size of array is negative" } + p = new (p) char [i4][5]; // { dg-error "size of array is negative" } + p = new (p) char [i6][i7]; // { dg-error "size of array is negative" } + + p = new (p) A [i1]; // { dg-error "size of array is negative" } + p = new (p) A [2][i3]; // { dg-error "size of array is negative" } + p = new (p) A [i4][5]; // { dg-error "size of array is negative" } + p = new (p) A [i6][i7]; // { dg-error "size of array is negative" } + + p = new (p) B [i1]; // { dg-error "size of array is negative" } + p = new (p) B [2][i3]; // { dg-error "size of array is negative" } + p = new (p) B [i4][5]; // { dg-error "size of array is negative" } + p = new (p) B [i6][i7]; // { dg-error "size of array is negative" } + + p = new (&b) B [i1]; // { dg-error "size of array is negative" } + p = new (&b) B [2][i3]; // { dg-error "size of array is negative" } + p = new (&b) B [i4][5]; // { dg-error "size of array is negative" } + p = new (&b) B [i6][i7]; // { dg-error "size of array is negative" } + + p = new short [i1 - 2]; // { dg-error "size of array is negative" } + p = new (p) bool [i2 - 3]; // { dg-error "size of array is negative" } + p = new A [2 < 1 ? i1 : i2]; // { dg-error "size of array is negative" } + p = new (p) B [2 + i3 * 2]; // { dg-error "size of array is negative" } + p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is negative" } +} + +void test_constexpr () +{ + B b; + +#if __cplusplus >= 201103L + + // Verify that a constant expression that is "a prvalue core constant + // expression whose value is an object where, for that object and its + // subobjects each non-static data member of reference type refers to + // an object with static storage duration." + static constexpr struct S { + int i_; + constexpr S (int i): i_ (i) { } + constexpr operator int () const { return i_; } + } s1 (-1), s2 (-2), s3 (-3), s4 (-4), s5 (-5), s6 (-6), s7 (-7); +#else + // C++ 11 constexpr is not available, fall back on plain ole enum. + enum { s1 = -1, s2 = -2, s3 = -3, s4 = -4, s5 = -5, s6 = -6, s7 = -7 }; +#endif + + // Verify constant expression. + p = new char [s1]; // { dg-error "size of array is negative" } + p = new char [2][s3]; // { dg-error "size of array is negative" } + p = new char [s4][5]; // { dg-error "size of array is negative" } + p = new char [s6][s7]; // { dg-error "size of array is negative" } + + p = new (p) char [s1]; // { dg-error "size of array is negative" } + p = new (p) char [2][s3]; // { dg-error "size of array is negative" } + p = new (p) char [s4][5]; // { dg-error "size of array is negative" } + p = new (p) char [s6][s7]; // { dg-error "size of array is negative" } + + p = new (p) A [s1]; // { dg-error "size of array is negative" } + p = new (p) A [2][s3]; // { dg-error "size of array is negative" } + p = new (p) A [s4][5]; // { dg-error "size of array is negative" } + p = new (p) A [s6][s7]; // { dg-error "size of array is negative" } + + p = new (p) B [s1]; // { dg-error "size of array is negative" } + p = new (p) B [2][s3]; // { dg-error "size of array is negative" } + p = new (p) B [s4][5]; // { dg-error "size of array is negative" } + p = new (p) B [s6][s7]; // { dg-error "size of array is negative" } + + p = new (&b) B [s1]; // { dg-error "size of array is negative" } + p = new (&b) B [2][s3]; // { dg-error "size of array is negative" } + p = new (&b) B [s4][5]; // { dg-error "size of array is negative" } + p = new (&b) B [s6][s7]; // { dg-error "size of array is negative" } + + p = new int [s1 + s2]; // { dg-error "size of array is negative" } + p = new (p) long [2 * s3]; // { dg-error "size of array is negative" } + p = new A [s2 < s1 ? s1 : s2]; // { dg-error "size of array is negative" } + p = new (p) B [s7 - s2 * 2]; // { dg-error "size of array is negative" } + p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array is negative" } +} diff --git a/gcc/testsuite/g++.dg/init/new44.C b/gcc/testsuite/g++.dg/init/new44.C new file mode 100644 index 0000000..d6ff86a --- /dev/null +++ b/gcc/testsuite/g++.dg/init/new44.C @@ -0,0 +1,532 @@ +// { dg-do compile } + +// Test for PR c++/67927 - array new expression with excessive number +// of elements not diagnosed. + +// GCC uses a different maximum value at compile time and at runtime: +// 1) The compile-time maximum, MAX, is SIZE_MAX / 2 minus the size +// of a cookie (sizeof (size_t)). Exceeding the compile-time +// maximum is ill-formed and diagnosed. This test verifies this +// diagnostic. +// 2) The runtime runtime maximum is the most significant 7 bits, +// starting with the first most significant non-zero bit, of +// the dividend of the compile-time constant MAX and the product +// of the constant array dimensions and the element size, minus +// the size of the "cookie." This is also roughly (though not +// exactly) SIZE_MAX / 2. Exceeding the runtime maximum is +// diagnosed at runtime by throwing a bad_array_new_length +// exception. +// The cookie is the number of elements in the array, and is +// only added for non-POD types, but the its size factors into +// the maximum size formula regardless. + +// See also PR c++/19351 - integer overflow in operator new[]. + +// For convenience. +#define MAX __SIZE_MAX__ + +typedef __typeof__ (sizeof 0) size_t; + +void* operator new (size_t, void*); +void* operator new[] (size_t, void*); + +void *p; + +// Exercise new expression with one-dimensional arrays of char. +static void __attribute__ ((used)) +test_one_dim_char_array () +{ + p = new char [MAX]; // { dg-error "size of array" } + p = new char [MAX - 1]; // { dg-error "size of array" } + p = new char [MAX - 2]; // { dg-error "size of array" } + p = new char [MAX - 99]; // { dg-error "size of array" } + p = new char [MAX / 2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 1]; // { dg-error "size of array" } + p = new char [MAX / 2 - 2]; // { dg-error "size of array" } + + // Avoid testing the expressions below since whether or not they + // are accepted depends on the precision of size_t (which also + // determines the size of the cookie). + // p = new char [MAX / 2 - 3]; + // p = new char [MAX / 2 - 4]; + // p = new char [MAX / 2 - 5]; + // p = new char [MAX / 2 - 6]; + + // The following expressions are accepted on ILP32 as well LP64 + // (they will be diagnosed on LP128 if there ever is such a data + // model). + p = new char [MAX / 2 - 7]; // okay + p = new char [MAX / 2 - 8]; // okay +} + +static void __attribute__ ((used)) +test_one_dim_short_array () +{ + p = new short [MAX]; // { dg-error "size of array" } + p = new short [MAX - 1]; // { dg-error "size of array" } + p = new short [MAX - 2]; // { dg-error "size of array" } + p = new short [MAX - 99]; // { dg-error "size of array" } + p = new short [MAX / 2]; // { dg-error "size of array" } + p = new short [MAX / 2 - 1]; // { dg-error "size of array" } + p = new short [MAX / 2 - 2]; // { dg-error "size of array" } + p = new short [MAX / 2 - 3]; // { dg-error "size of array" } + p = new short [MAX / 2 - 4]; // { dg-error "size of array" } + p = new short [MAX / 2 - 5]; // { dg-error "size of array" } + p = new short [MAX / 2 - 6]; // { dg-error "size of array" } + p = new short [MAX / 2 - 7]; // { dg-error "size of array" } + p = new short [MAX / 2 - 8]; // { dg-error "size of array" } + p = new short [MAX / 4]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new short [MAX / 4 - 1]; + + p = new short [MAX / 4 - 4]; // okay +} + +// Exercise new expression with two-dimensional arrays or char. +static void __attribute__ ((used)) +test_two_dim_char_array () +{ + p = new char [1][MAX]; // { dg-error "size of array" } + p = new char [1][MAX - 1]; // { dg-error "size of array" } + p = new char [1][MAX - 2]; // { dg-error "size of array" } + p = new char [1][MAX - 99]; // { dg-error "size of array" } + p = new char [1][MAX / 2]; // { dg-error "size of array" } + p = new char [1][MAX / 2 - 1]; // { dg-error "size of array" } + p = new char [1][MAX / 2 - 2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new char [1][MAX / 2 - 3]; + // p = new char [1][MAX / 2 - 4]; + // p = new char [1][MAX / 2 - 5]; + // p = new char [1][MAX / 2 - 6]; + + p = new char [1][MAX / 2 - 7]; // okay + p = new char [1][MAX / 2 - 8]; // okay + + p = new char [2][MAX]; // { dg-error "size of array" } + p = new char [2][MAX - 1]; // { dg-error "size of array" } + p = new char [2][MAX - 2]; // { dg-error "size of array" } + p = new char [2][MAX / 2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 1]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 7]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 8]; // { dg-error "size of array" } + + p = new char [MAX][MAX]; // { dg-error "size of array" } + p = new char [MAX][MAX - 1]; // { dg-error "size of array" } + p = new char [MAX][MAX - 2]; // { dg-error "size of array" } + p = new char [MAX][MAX / 2]; // { dg-error "size of array" } + p = new char [MAX][MAX / 2 - 1]; // { dg-error "size of array" } + p = new char [MAX][MAX / 2 - 2]; // { dg-error "size of array" } + p = new char [MAX][MAX / 2 - 7]; // { dg-error "size of array" } + p = new char [MAX][MAX / 2 - 8]; // { dg-error "size of array" } + p = new char [MAX][2]; // { dg-error "size of array" } + p = new char [MAX][1]; // { dg-error "size of array" } + p = new char [MAX / 2][1]; // { dg-error "size of array" } + p = new char [MAX / 2 - 1][1]; // { dg-error "size of array" } + p = new char [MAX / 2 - 2][1]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new char [MAX / 2 - 3][1]; + // p = new char [MAX / 2 - 4][1]; + // p = new char [MAX / 2 - 5][1]; + // p = new char [MAX / 2 - 6][1]; + + p = new char [MAX / 2 - 7][1]; // okay + p = new char [MAX / 2 - 8][1]; // okay +} + + +// Exercise new expression with three-dimensional arrays. +static __attribute__ ((used)) void +test_three_dim_char_array () +{ + p = new char [1][1][MAX]; // { dg-error "size of array" } + p = new char [1][1][MAX - 1]; // { dg-error "size of array" } + p = new char [1][1][MAX - 2]; // { dg-error "size of array" } + p = new char [1][1][MAX - 99]; // { dg-error "size of array" } + p = new char [1][1][MAX / 2]; // { dg-error "size of array" } + p = new char [1][1][MAX / 2 - 1]; // { dg-error "size of array" } + p = new char [1][1][MAX / 2 - 2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new char [1][1][MAX / 2 - 3]; + // p = new char [1][1][MAX / 2 - 4]; + // p = new char [1][1][MAX / 2 - 5]; + // p = new char [1][1][MAX / 2 - 6]; + + p = new char [1][1][MAX / 2 - 7]; // okay + p = new char [1][1][MAX / 2 - 8]; // okay + + p = new char [1][2][MAX]; // { dg-error "size of array" } + p = new char [1][2][MAX - 1]; // { dg-error "size of array" } + p = new char [1][2][MAX - 2]; // { dg-error "size of array" } + p = new char [1][2][MAX - 99]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2 - 1]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2 - 2]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2 - 3]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2 - 4]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2 - 5]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2 - 6]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2 - 7]; // { dg-error "size of array" } + p = new char [1][2][MAX / 2 - 8]; // { dg-error "size of array" } + p = new char [1][2][MAX / 4]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new char [1][2][MAX / 4 - 1]; + // p = new char [1][2][MAX / 4 - 2]; + + p = new char [1][2][MAX / 4 - 3]; // okay + p = new char [1][2][MAX / 4 - 4]; // okay + + p = new char [2][1][MAX]; // { dg-error "size of array" } + p = new char [2][1][MAX - 1]; // { dg-error "size of array" } + p = new char [2][1][MAX - 2]; // { dg-error "size of array" } + p = new char [2][1][MAX - 99]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2 - 1]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2 - 2]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2 - 3]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2 - 4]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2 - 5]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2 - 6]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2 - 7]; // { dg-error "size of array" } + p = new char [2][1][MAX / 2 - 8]; // { dg-error "size of array" } + p = new char [2][1][MAX / 4]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new char [2][1][MAX / 4 - 1]; + // p = new char [2][1][MAX / 4 - 2]; + + p = new char [2][1][MAX / 4 - 3]; // okay + p = new char [2][1][MAX / 4 - 4]; // okay + + p = new char [2][2][MAX]; // { dg-error "size of array" } + p = new char [2][2][MAX - 1]; // { dg-error "size of array" } + p = new char [2][2][MAX - 2]; // { dg-error "size of array" } + p = new char [2][2][MAX - 99]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2 - 1]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2 - 2]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2 - 3]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2 - 4]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2 - 5]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2 - 6]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2 - 7]; // { dg-error "size of array" } + p = new char [2][2][MAX / 2 - 8]; // { dg-error "size of array" } + p = new char [2][2][MAX / 4]; // { dg-error "size of array" } + p = new char [2][2][MAX / 4 - 1]; // { dg-error "size of array" } + p = new char [2][2][MAX / 4 - 2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new char [2][2][MAX / 8]; + // p = new char [2][2][MAX / 8 - 1]; + + p = new char [2][2][MAX / 8 - 2]; + p = new char [2][2][MAX / 8 - 3]; + + p = new char [2][MAX][2]; // { dg-error "size of array" } + p = new char [2][MAX - 1][2]; // { dg-error "size of array" } + p = new char [2][MAX - 2][2]; // { dg-error "size of array" } + p = new char [2][MAX - 99][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 1][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 2][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 3][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 4][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 5][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 6][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 7][2]; // { dg-error "size of array" } + p = new char [2][MAX / 2 - 8][2]; // { dg-error "size of array" } + p = new char [2][MAX / 4][2]; // { dg-error "size of array" } + p = new char [2][MAX / 4 - 1][2]; // { dg-error "size of array" } + p = new char [2][MAX / 4 - 2][2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new char [2][MAX / 8][2]; + // p = new char [2][MAX / 8 - 1][2]; + + p = new char [2][MAX / 8 - 2][2]; + p = new char [2][MAX / 8 - 3][2]; + + p = new char [MAX][2][2]; // { dg-error "size of array" } + p = new char [MAX - 1][2][2]; // { dg-error "size of array" } + p = new char [MAX - 2][2][2]; // { dg-error "size of array" } + p = new char [MAX - 99][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 1][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 2][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 3][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 4][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 5][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 6][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 7][2][2]; // { dg-error "size of array" } + p = new char [MAX / 2 - 8][2][2]; // { dg-error "size of array" } + p = new char [MAX / 4][2][2]; // { dg-error "size of array" } + p = new char [MAX / 4 - 1][2][2]; // { dg-error "size of array" } + p = new char [MAX / 4 - 2][2][2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new char [MAX / 8][2][2]; + // p = new char [MAX / 8 - 1][2][2]; + + p = new char [MAX / 8 - 2][2][2]; + p = new char [MAX / 8 - 3][2][2]; + + p = new char [MAX][MAX][MAX]; // { dg-error "size of array" } + p = new char [MAX][MAX][MAX / 2]; // { dg-error "size of array" } + p = new char [MAX][MAX / 2][MAX]; // { dg-error "size of array" } + p = new char [MAX][MAX / 2][MAX / 2]; // { dg-error "size of array" } + p = new char [MAX / 2][MAX / 2][MAX / 2]; // { dg-error "size of array" } +} + +// Exercise new expression with N-dimensional arrays where N is +// sizeof(size_t). +static __attribute__ ((used)) void +test_N_dim_char_array () +{ +#if __SIZEOF_SIZE_T__ == 8 + enum { N = 256 }; +#else + enum { N = 16 }; +#endif + + p = new char [N][N][N][N][N][N][N]; + p = new char [N / 2][2][N][N][N][N][N][N]; + p = new char [N - 1][N / 2][N][N][N][N][N][N]; + p = new char [N / 2][N][N][N][N][N][N][N]; // { dg-error "size of array" } + p = new char [N - 1][N][N][N][N][N][N][N]; // { dg-error "size of array" } + p = new char [N] [N][N][N][N][N][N][N]; // { dg-error "size of array" } +} + +typedef struct Byte { + char c; + + void* operator new (size_t, void*); + void* operator new[] (size_t, void*); +} B; + +void* operator new (size_t, B*); +void* operator new[] (size_t, B*); + +// Exercise placement new expression with one-dimensional arrays of a struct. +static void __attribute__ ((used)) +test_one_dim_byte_array (void *p) +{ + p = new (p) B [MAX]; // { dg-error "size of array" } + p = new (p) B [MAX - 1]; // { dg-error "size of array" } + p = new (p) B [MAX - 2]; // { dg-error "size of array" } + p = new (p) B [MAX - 99]; // { dg-error "size of array" } + p = new (p) B [MAX / 2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 1]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 2]; // { dg-error "size of array" } + + // Avoid testing the expressions below since whether or not they + // are accepted depends on the precision of size_t (which determines + // the size of the cookie). + // p = new (p) B [MAX / 2 - 3]; + // p = new (p) B [MAX / 2 - 4]; + // p = new (p) B [MAX / 2 - 5]; + // p = new (p) B [MAX / 2 - 6]; + + // The following expressions are accepted on ILP32 as well LP64 + // (they will be diagnosed on LP128 if there ever is such a data + // model). + p = new (p) B [MAX / 2 - 7]; // okay + p = new (p) B [MAX / 2 - 8]; // okay +} + +// Exercise placement new expression with two-dimensional arrays. +static void __attribute__ ((used)) +test_placement_two_dim_byte_struct_array (void *p) +{ + p = new (p) B [1][MAX]; // { dg-error "size of array" } + p = new (p) B [1][MAX - 1]; // { dg-error "size of array" } + p = new (p) B [1][MAX - 2]; // { dg-error "size of array" } + p = new (p) B [1][MAX - 99]; // { dg-error "size of array" } + p = new (p) B [1][MAX / 2]; // { dg-error "size of array" } + p = new (p) B [1][MAX / 2 - 1]; // { dg-error "size of array" } + p = new (p) B [1][MAX / 2 - 2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new (p) B [1][MAX / 2 - 3]; + // p = new (p) B [1][MAX / 2 - 4]; + // p = new (p) B [1][MAX / 2 - 5]; + // p = new (p) B [1][MAX / 2 - 6]; + + p = new (p) B [1][MAX / 2 - 7]; // okay + p = new (p) B [1][MAX / 2 - 8]; // okay + + p = new (p) B [2][MAX]; // { dg-error "size of array" } + p = new (p) B [2][MAX - 1]; // { dg-error "size of array" } + p = new (p) B [2][MAX - 2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 1]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 7]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 8]; // { dg-error "size of array" } + + p = new (p) B [MAX][MAX]; // { dg-error "size of array" } + p = new (p) B [MAX][MAX - 1]; // { dg-error "size of array" } + p = new (p) B [MAX][MAX - 2]; // { dg-error "size of array" } + p = new (p) B [MAX][MAX / 2]; // { dg-error "size of array" } + p = new (p) B [MAX][MAX / 2 - 1]; // { dg-error "size of array" } + p = new (p) B [MAX][MAX / 2 - 2]; // { dg-error "size of array" } + p = new (p) B [MAX][MAX / 2 - 7]; // { dg-error "size of array" } + p = new (p) B [MAX][MAX / 2 - 8]; // { dg-error "size of array" } + p = new (p) B [MAX][2]; // { dg-error "size of array" } + p = new (p) B [MAX][1]; // { dg-error "size of array" } + p = new (p) B [MAX / 2][1]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 1][1]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 2][1]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new (p) B [MAX / 2 - 3][1]; + // p = new (p) B [MAX / 2 - 4][1]; + // p = new (p) B [MAX / 2 - 5][1]; + // p = new (p) B [MAX / 2 - 6][1]; + + p = new (p) B [MAX / 2 - 7][1]; // okay + p = new (p) B [MAX / 2 - 8][1]; // okay +} + + +// Exercise placement new expression with three-dimensional arrays. +static __attribute__ ((used)) void +test_placement_three_dim_byte_struct_array (void *p) +{ + p = new (p) B [1][1][MAX]; // { dg-error "size of array" } + p = new (p) B [1][1][MAX - 1]; // { dg-error "size of array" } + p = new (p) B [1][1][MAX - 2]; // { dg-error "size of array" } + p = new (p) B [1][1][MAX - 99]; // { dg-error "size of array" } + p = new (p) B [1][1][MAX / 2]; // { dg-error "size of array" } + p = new (p) B [1][1][MAX / 2 - 1]; // { dg-error "size of array" } + p = new (p) B [1][1][MAX / 2 - 2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new (p) B [1][1][MAX / 2 - 3]; + // p = new (p) B [1][1][MAX / 2 - 4]; + // p = new (p) B [1][1][MAX / 2 - 5]; + // p = new (p) B [1][1][MAX / 2 - 6]; + + p = new (p) B [1][1][MAX / 2 - 7]; // okay + p = new (p) B [1][1][MAX / 2 - 8]; // okay + + p = new (p) B [1][2][MAX]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX - 1]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX - 2]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX - 99]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2 - 1]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2 - 2]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2 - 3]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2 - 4]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2 - 5]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2 - 6]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2 - 7]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 2 - 8]; // { dg-error "size of array" } + p = new (p) B [1][2][MAX / 4]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new (p) B [1][2][MAX / 4 - 1]; + // p = new (p) B [1][2][MAX / 4 - 2]; + + p = new (p) B [1][2][MAX / 4 - 3]; // okay + p = new (p) B [1][2][MAX / 4 - 4]; // okay + + p = new (p) B [2][1][MAX]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX - 1]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX - 2]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX - 99]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2 - 1]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2 - 2]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2 - 3]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2 - 4]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2 - 5]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2 - 6]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2 - 7]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 2 - 8]; // { dg-error "size of array" } + p = new (p) B [2][1][MAX / 4]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new (p) B [2][1][MAX / 4 - 1]; + // p = new (p) B [2][1][MAX / 4 - 2]; + + p = new (p) B [2][1][MAX / 4 - 3]; // okay + p = new (p) B [2][1][MAX / 4 - 4]; // okay + + p = new (p) B [2][2][MAX]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX - 1]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX - 2]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX - 99]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2 - 1]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2 - 2]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2 - 3]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2 - 4]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2 - 5]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2 - 6]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2 - 7]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 2 - 8]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 4]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 4 - 1]; // { dg-error "size of array" } + p = new (p) B [2][2][MAX / 4 - 2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new (p) B [2][2][MAX / 8]; + // p = new (p) B [2][2][MAX / 8 - 1]; + + p = new (p) B [2][2][MAX / 8 - 2]; + p = new (p) B [2][2][MAX / 8 - 3]; + + p = new (p) B [2][MAX][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX - 1][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX - 2][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX - 99][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 1][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 2][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 3][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 4][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 5][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 6][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 7][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 2 - 8][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 4][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 4 - 1][2]; // { dg-error "size of array" } + p = new (p) B [2][MAX / 4 - 2][2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new (p) B [2][MAX / 8][2]; + // p = new (p) B [2][MAX / 8 - 1][2]; + + p = new (p) B [2][MAX / 8 - 2][2]; + p = new (p) B [2][MAX / 8 - 3][2]; + + p = new (p) B [MAX][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX - 1][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX - 2][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX - 99][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 1][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 2][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 3][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 4][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 5][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 6][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 7][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 2 - 8][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 4][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 4 - 1][2][2]; // { dg-error "size of array" } + p = new (p) B [MAX / 4 - 2][2][2]; // { dg-error "size of array" } + + // Avoid exercising data model-dependent expressions. + // p = new (p) B [MAX / 8][2][2]; + // p = new (p) B [MAX / 8 - 1][2][2]; + + p = new (p) B [MAX / 8 - 2][2][2]; + p = new (p) B [MAX / 8 - 3][2][2]; +} diff --git a/gcc/testsuite/g++.dg/init/new45.C b/gcc/testsuite/g++.dg/init/new45.C new file mode 100644 index 0000000..92dac18 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/new45.C @@ -0,0 +1,106 @@ +// { dg-do compile } +// { dg-options "-O1" } +// { dg-final { scan-assembler-not "abort" } } + +typedef __SIZE_TYPE__ size_t; + +extern "C" { + void abort (); + void* malloc (size_t); +} + +struct UDClass { + static int n; + UDClass () { ++n; } + virtual ~UDClass () { --n; } +}; + +int UDClass::n; + +struct POD { + char buf [sizeof (UDClass)]; +}; + +enum { N = 123 }; + +inline __attribute__ ((always_inline)) +void* operator new[] (size_t n) +{ + // Verify that array new is invoked with an argument large enough + // for the array and a size_t cookie to store the number of elements. + // (This holds for classes with user-defined types but not POD types). + if (n != N * sizeof (UDClass) + sizeof n) abort (); + return malloc (n); +} + +inline __attribute__ ((always_inline)) +void* operator new[] (size_t n, void *p) +{ + // Verify that the default placement array new is invoked with + // an argument just large enough for the array (and no cookie), + // regardless of whether the type is a POD or class with a user + // defined ctor. + if (n != N * sizeof (UDClass)) abort (); + return p; +} + +inline __attribute__ ((always_inline)) +void* operator new[] (size_t n, POD *p) +{ + // Verify that placement array new overload for a POD type is + // invoked with an argument large enough for the array and + // a cookie. + if (n != N * sizeof (POD)) abort (); + return p; +} + +inline __attribute__ ((always_inline)) +void* operator new[] (size_t n, UDClass *p) +{ + // Verify that placement array new overload for a class type with + // a user-defined ctor and dtor is invoked with an argument large + // enough for the array and a cookie. + if (n != N * sizeof (UDClass) + sizeof n) abort (); + return p; +} + +// UDClassllocate a sufficiently large buffer to construct arrays into. +static unsigned char buf [N * N]; + +POD* test_new_POD () +{ + // Avoid testing PODs since for those, the global new is invoked + // without the overhead of a cookie. + // return new POD [N]; + return 0; +} + +POD* test_default_placement_new_POD () +{ + // Vefify that no overhead is allocated. + return new (buf) POD [N]; +} + +POD* test_overloaded_placement_new_POD () +{ + // Vefify that no overhead is allocated. + return new ((POD*)buf) POD [N]; +} + +UDClass* test_new_UDClass () +{ + // Vefify that space for a cookie is allocated. + return new UDClass [N]; +} + +UDClass* test_default_placement_new_UDClass () +{ + // Vefify that no overhead is allocated. + return new (buf) UDClass [N]; +} + +UDClass* test_overloaded_placement_new_UDClass () +{ + // Vefify that space for a cookie is allocated. + return new ((UDClass*)buf) UDClass [N]; +} diff --git a/gcc/testsuite/g++.dg/other/new-size-type.C b/gcc/testsuite/g++.dg/other/new-size-type.C index 04933fd..ad4dc10 100644 --- a/gcc/testsuite/g++.dg/other/new-size-type.C +++ b/gcc/testsuite/g++.dg/other/new-size-type.C @@ -5,6 +5,5 @@ const char* foo() { - return new char[~static_cast(0)];// { dg-bogus "large" } + return new char[~static_cast(0)];// { dg-error "size of array" } } -