From 342fac9537c6a75e65fe62943ba84b81bddede3f Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 13 Apr 2016 23:26:41 +0000 Subject: [PATCH] PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements PR c++/70019 - VLA size overflow not detected PR c++/70588 - SIGBUS on a VLA larger than SIZE_MAX / 2 gcc/testsuite/ChangeLog: 2016-04-13 Martin Sebor PR c++/69517 PR c++/70019 PR c++/70588 * c-c++-common/ubsan/vla-1.c (main): Catch exceptions. * g++.dg/cpp1y/vla11.C: New test. * g++.dg/cpp1y/vla12.C: New test. * g++.dg/cpp1y/vla13.C: New test. * g++.dg/cpp1y/vla14.C: New test. * g++.dg/cpp1y/vla3.C: Restore deleted test. * gcc/testsuite/g++.dg/init/array24.C: Fully brace VLA initializer. * g++.dg/ubsan/vla-1.C: Disable exceptions. gcc/cp/ChangeLog: 2016-04-13 Martin Sebor PR c++/69517 PR c++/70019 PR c++/70588 * cp-tree.h (throw_bad_array_length, build_vla_check): Declare new functions. * decl.c (check_initializer, cp_finish_decl): Call them. (reshape_init_r): Reject incompletely braced intializer-lists for VLAs. * init.c (throw_bad_array_length, build_vla_check) (build_vla_size_check, build_vla_init_check): Define new functions. * typeck2.c (split_nonconstant_init_1): Use variably_modified_type_p() to detect a VLA. (store_init_value): Same. gcc/doc/ChangeLog: 2016-04-13 Martin Sebor PR c++/69517 PR c++/70019 PR c++/70588 * extend.texi (Variable Length): Document C++ specifics. libstdc++-v3/ChangeLog: 2016-04-13 Martin Sebor PR c++/69517 * testsuite/25_algorithms/rotate/moveable2.cc: Make sure VLA upper bound is positive. From-SVN: r234966 --- gcc/ChangeLog | 7 + gcc/cp/ChangeLog | 16 + gcc/cp/cp-tree.h | 2 + gcc/cp/decl.c | 45 +- gcc/cp/init.c | 315 +++++++++ gcc/cp/typeck2.c | 4 +- gcc/doc/extend.texi | 38 +- gcc/testsuite/ChangeLog | 14 + gcc/testsuite/c-c++-common/ubsan/vla-1.c | 30 +- gcc/testsuite/g++.dg/cpp1y/vla11.C | 711 +++++++++++++++++++++ gcc/testsuite/g++.dg/cpp1y/vla12.C | 99 +++ gcc/testsuite/g++.dg/cpp1y/vla13.C | 260 ++++++++ gcc/testsuite/g++.dg/cpp1y/vla14.C | 48 ++ gcc/testsuite/g++.dg/cpp1y/vla3.C | 43 ++ gcc/testsuite/g++.dg/init/array24.C | 2 +- gcc/testsuite/g++.dg/ubsan/vla-1.C | 5 +- libstdc++-v3/ChangeLog | 6 + .../testsuite/25_algorithms/rotate/moveable2.cc | 3 +- 18 files changed, 1628 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/vla11.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/vla12.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/vla13.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/vla14.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/vla3.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 26db5fe..a3c6c12 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2016-04-13 Martin Sebor + + PR c++/69517 + PR c++/70019 + PR c++/70588 + * doc/extend.texi (Variable Length): Document C++ specifics. + 2016-04-13 Jakub Jelinek PR c++/70641 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c9929b63..866b4f2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2016-04-13 Martin Sebor + + PR c++/69517 + PR c++/70019 + PR c++/70588 + * cp-tree.h (throw_bad_array_length, build_vla_check): Declare new + functions. + * decl.c (check_initializer, cp_finish_decl): Call them. + (reshape_init_r): Reject incompletely braced intializer-lists + for VLAs. + * init.c (throw_bad_array_length, build_vla_check) + (build_vla_size_check, build_vla_init_check): Define new functions. + * typeck2.c (split_nonconstant_init_1): Use variably_modified_type_p() + to detect a VLA. + (store_init_value): Same. + 2016-04-13 Jason Merrill Warn about empty parameter ABI with -Wabi=9. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8d721c7..87e3ea0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5950,6 +5950,7 @@ extern tree build_value_init_noctor (tree, tsubst_flags_t); extern tree get_nsdmi (tree, bool); extern tree build_offset_ref (tree, tree, bool, tsubst_flags_t); +extern tree throw_bad_array_length (void); extern tree throw_bad_array_new_length (void); extern tree build_new (vec **, tree, tree, vec **, int, @@ -5971,6 +5972,7 @@ extern tree scalar_constant_value (tree); extern tree decl_really_constant_value (tree); extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool); extern tree build_vtbl_address (tree); +extern tree build_vla_check (tree, tree = NULL_TREE); /* in lex.c */ extern void cxx_dup_lang_specific_decl (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 7099199..42e853f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5896,6 +5896,16 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p, } } + if (variably_modified_type_p (type, NULL_TREE)) + { + /* Require VLAs to have their initializers fully braced + to avoid initializing the wrong elements. */ + if (complain & tf_error) + error ("missing braces around initializer for a variable length " + "array %qT", type); + return error_mark_node; + } + warning (OPT_Wmissing_braces, "missing braces around initializer for %qT", type); } @@ -6048,6 +6058,10 @@ check_initializer (tree decl, tree init, int flags, vec **cleanups) /* There is no way to make a variable-sized class type in GNU C++. */ gcc_assert (TREE_CONSTANT (TYPE_SIZE (type))); + /* Initializer exression used to check invalid VLA bounds and excess + initializer elements. */ + tree saved_init_for_vla_check = NULL_TREE; + if (init && BRACE_ENCLOSED_INITIALIZER_P (init)) { int init_len = vec_safe_length (CONSTRUCTOR_ELTS (init)); @@ -6199,7 +6213,9 @@ check_initializer (tree decl, tree init, int flags, vec **cleanups) && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl))) warning (0, "array %qD initialized by parenthesized string literal %qE", decl, DECL_INITIAL (decl)); - init = NULL; + + saved_init_for_vla_check = init; + init = NULL_TREE; } } else @@ -6213,6 +6229,33 @@ check_initializer (tree decl, tree init, int flags, vec **cleanups) check_for_uninitialized_const_var (decl); } + if (TREE_CODE (type) == ARRAY_TYPE + && variably_modified_type_p (type, NULL_TREE) + && !processing_template_decl) + { + /* Statically check for overflow in VLA bounds and build + an expression that checks at runtime whether the VLA + is erroneous due to invalid (runtime) bounds. + Another expression to check for excess initializers + is built in build_vec_init. */ + tree check = build_vla_check (TREE_TYPE (decl), saved_init_for_vla_check); + + if (flag_exceptions && current_function_decl + /* Avoid instrumenting constexpr functions for now. + Those must be checked statically, and the (non- + constexpr) dynamic instrumentation would cause + them to be rejected. See c++/70507. */ + && !DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + { + /* Use the runtime check only when exceptions are enabled. + Otherwise let bad things happen... */ + check = build3 (COND_EXPR, void_type_node, check, + throw_bad_array_length (), void_node); + + finish_expr_stmt (check); + } + } + if (init && init != error_mark_node) init_code = build2 (INIT_EXPR, type, decl, init); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 5997d53..ec19d72 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2262,6 +2262,20 @@ diagnose_uninitialized_cst_or_ref_member (tree type, bool using_new, bool compla return diagnose_uninitialized_cst_or_ref_member_1 (type, type, using_new, complain); } +/* Call __cxa_throw_bad_array_length to indicate that the size calculation + in the bounds of a variable length array overflowed. */ + +tree +throw_bad_array_length (void) +{ + tree fn = get_identifier ("__cxa_throw_bad_array_length"); + if (!get_global_value_if_present (fn, &fn)) + fn = push_throw_library_fn (fn, build_function_type_list (void_type_node, + NULL_TREE)); + + return build_cxx_call (fn, 0, NULL, tf_warning_or_error); +} + /* Call __cxa_bad_array_new_length to indicate that the size calculation overflowed. Pretend it returns sizetype so that it plays nicely in the COND_EXPR. */ @@ -4709,3 +4723,304 @@ build_vec_delete (tree base, tree maxindex, return rval; } + + +/* The implementation of build_vla_check() that recursively builds + an expression to determine whether the VLA TYPE is erroneous due + either to its bounds being invalid or to integer overflow in + the computation of its total size. + CHECK is the boolean expression being built, initialized to + boolean_false_node. + VLASIZE is used internally to pass the incrementally computed + size of the VLA object down to its recursive invocations. + MAX_VLASIZE is the maximum valid size of the VLA in bytes. + CST_SIZE is the product of the VLA's constant dimensions. */ + +static tree +build_vla_size_check (tree check, + tree type, + tree vlasize, + tree max_vlasize, + offset_int *cst_size) +{ + tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW); + + tree vlasizeaddr = build_unary_op (input_location, ADDR_EXPR, vlasize, 0); + + bool overflow = false; + + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Compute the upper bound of this array type. */ + tree inner_nelts = array_type_nelts_top (type); + tree inner_nelts_cst = maybe_constant_value (inner_nelts); + + if (TREE_CODE (inner_nelts_cst) == INTEGER_CST) + { + /* The upper bound is a constant expression. Compute the product + of the constant upper bounds seen so far so that overflow can + be diagnosed. */ + offset_int result = wi::mul (wi::to_offset (inner_nelts_cst), + *cst_size, SIGNED, &overflow); + *cst_size = overflow ? 0 : result; + } + + /* Check for overflow in the VLAs (runtime) upper bounds. */ + tree vflowcheck = build_call_expr (vmul, 3, inner_nelts, + vlasize, vlasizeaddr); + + check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, + check, vflowcheck); + + /* Recursively check for overflow in the remaining major bounds. */ + check = build_vla_size_check (check, TREE_TYPE (type), + vlasize, max_vlasize, + cst_size); + } + else + { + /* Get the size of the VLA element type in bytes. */ + tree typesize = TYPE_SIZE_UNIT (type); + + /* See if the size, when multipled by the product of the VLA's + constant dimensions, is within range of size_t. If not, + the VLA is definitely erroneous amd must be diagnosed at + compile time. */ + offset_int result = wi::mul (wi::to_offset (typesize), *cst_size, + SIGNED, &overflow); + *cst_size = overflow ? 0 : result; + + /* Multiply the (non-constant) VLA size so far by the element size, + checking for overflow, and replacing the value of vlasize with + the product in the absence of overflow. This size is the total + runtime size of the VLA in bytes. */ + tree vflowcheck = build_call_expr (vmul, 3, typesize, + vlasize, vlasizeaddr); + + check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, + check, vflowcheck); + + /* Check to see if the final VLA size exceeds the maximum. */ + tree sizecheck = fold_build2 (LT_EXPR, boolean_type_node, + max_vlasize, vlasize); + + check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, + check, sizecheck); + + /* Also check to see if the final array size is zero (the size + is unsigned so the earlier overflow check detects negative + values as well. */ + tree zerocheck = fold_build2 (EQ_EXPR, boolean_type_node, + vlasize, size_zero_node); + + check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, + check, zerocheck); + } + + /* Diagnose overflow determined at compile time. */ + if (overflow) + { + error ("integer overflow in variable array size"); + /* Reset to suppress any further diagnostics. */ + *cst_size = 0; + } + + return check; +} + +/* The implementation of build_vla_check() that recursively builds + an expression to determine whether the VLA initializer-list for + TYPE is erroneous due to excess initializers. + CHECK is the boolean expression being built, initialized to + the result of build_vla_size_check(). + INIT is the VLA initializer expression to check against TYPE. + On the first (non-recursive) call, INIT_ELTS is set either to 1, + or to the number of elements in the initializer-list for VLAs + of unspecified (major) bound. On subsequent (recursive) calls. + it is set to NULL and computed from the number of elements in + the (nested) initializer-list. +*/ + +static tree +build_vla_init_check (tree check, tree type, tree init, tree init_elts) +{ + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Compute the upper bound of this array type unless it has + already been computed by the caller for an array of unspecified + bound, as in 'T a[];' */ + tree inner_nelts = init_elts ? init_elts : array_type_nelts_top (type); + + size_t len; + + if (TREE_CODE (init) == CONSTRUCTOR) + { + /* The initializer of this array is itself an array. Build + an expression to check if the number of elements in the + initializer array exceeds the upper bound of the type + of the object being initialized. */ + if (vec *v = CONSTRUCTOR_ELTS (init)) + { + len = v->length (); + tree initelts = build_int_cstu (size_type_node, len); + tree initcheck = fold_build2 (LT_EXPR, boolean_type_node, + inner_nelts, initelts); + + check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, + check, initcheck); + + constructor_elt *ce; + HOST_WIDE_INT i; + + /* Iterate over all non-empty initializers in this array, + recursively building expressions to see if the elements + of each are in excess of the corresponding (runtime) + bound of the array type. */ + FOR_EACH_VEC_SAFE_ELT (v, i, ce) + check = build_vla_init_check (check, TREE_TYPE (type), + ce->value, NULL_TREE); + } + } + else if (TREE_CODE (init) == STRING_CST + && (len = TREE_STRING_LENGTH (init))) + { + /* The initializer of this array is a string. */ + tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init))); + len /= TYPE_PRECISION (ctype) / BITS_PER_UNIT; + + /* A C++ string literal initializer must have at most as many + characters as there are elements in the array, including + the terminating NUL. */ + tree initelts = build_int_cstu (size_type_node, len); + tree initcheck = fold_build2 (LT_EXPR, boolean_type_node, + inner_nelts, initelts); + check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, + check, initcheck); + } + else if (TREE_CODE (init) == ERROR_MARK) + { + // No checking is possible. + check = boolean_false_node; + } + else + { + /* What's this array initializer? */ + gcc_unreachable (); + } + } + + return check; +} + +/* Build an expression to determine whether the VLA TYPE is erroneous. + INIT is the VLA initializer expression or NULL_TREE when the VLA is + not initialized. */ + +tree +build_vla_check (tree type, tree init /* = NULL_TREE */) +{ + tree check = boolean_false_node; + + /* The product of all constant dimensions of the VLA, initialized + to either 1 in the common case or to the number of elements in + the VLA's initializer-list for VLAs of unspecified (major) + bound. */ + offset_int cst_size = 1; + + /* The initial size of the VLA to start the computation of the total + size with. Like CST_SIZE above, initialized to 1 or the number + of elements in the VLA's initializer-list for VLAs of unspecified + bound. */ + tree initial_size = size_one_node; + + /* For a VLA of unspecified (major) bound, the number of elements + it is initialized with determined from the initializer-list. */ + tree initial_elts = NULL_TREE; + + if (init) + { + /* Determine the upper bound of the VLA of unspecified bound, + as in 'T a[];' if this is such a VLA. Such a VLA can be + initialized with any number of elements but the number of + elements so determined must be used to check the total size + of the VLA. */ + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + + if (tree dom = TYPE_DOMAIN (type)) + if (tree max = TYPE_MAX_VALUE (dom)) + if (integer_zerop (max)) + { + if (TREE_CODE (init) == CONSTRUCTOR) + { + vec *v = CONSTRUCTOR_ELTS (init); + + /* Since the upper bound of every array must be positive + a VLA with an unspecified major bound must be initized + by a non-empty initializer list. */ + gcc_assert (v != NULL); + + cst_size = v->length (); + } + else if (TREE_CODE (init) == STRING_CST) + { + /* The initializer is a (possibly empty) string consisting + at a minumum of one character, the terminating NUL. + This condition implies a definition like + char s [][N] = ""; + which is an error but even though it has been diagnosed + by this point the initializer still winds up here. */ + size_t nchars = TREE_STRING_LENGTH (init); + tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init))); + nchars /= TYPE_PRECISION (ctype) / BITS_PER_UNIT; + + cst_size = nchars + 1; + } + + initial_elts = wide_int_to_tree (size_type_node, cst_size); + initial_size = initial_elts; + } + } + + /* Build a variable storing the total runtime size of the VLA and + initialize it either to 1 (in the common case) or to the number + of topmost elements in the initializer-list when the VLA is + an array of unspecified (major) bound. */ + tree vlasize = build_decl (input_location, + VAR_DECL, NULL_TREE, sizetype); + DECL_ARTIFICIAL (vlasize) = 1; + DECL_IGNORED_P (vlasize) = 1; + DECL_CONTEXT (vlasize) = current_function_decl; + DECL_INITIAL (vlasize) = initial_size; + vlasize = pushdecl (vlasize); + add_decl_expr (vlasize); + + /* Impose a lenient limit on the size of the biggest VLA in bytes. + FIXME: Tighten up the limit to make it more useful and make it + configurable for users with unusual requirements. */ + tree max_vlasize + = fold_build2 (RSHIFT_EXPR, size_type_node, + build_all_ones_cst (size_type_node), + integer_one_node); + + /* Build an expression that checks the runtime bounds of the VLA + for invalid values and the total size of the VLA for overflow. */ + check = build_vla_size_check (check, type, vlasize, max_vlasize, &cst_size); + + if (wi::ltu_p (wi::to_offset (max_vlasize), cst_size)) + { + /* Issue the warning only in the "topmost" (non-recursive) call + to avoid duplicating diagnostics. This is only a warning to + allow programs to be portable to more permissive environments. */ + warning (OPT_Wvla, "size of variable length array exceeds maximum " + "of %qE bytes", max_vlasize); + } + + if (init) + { + /* Build an expression that checks the VLA initializer expression + against the type of the VLA for excess elements. */ + check = build_vla_init_check (check, type, init, initial_elts); + } + + return check; +} diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index b921689..eba19ca 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -603,7 +603,7 @@ split_nonconstant_init_1 (tree dest, tree init) array_type_p = true; if ((TREE_SIDE_EFFECTS (init) && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) - || array_of_runtime_bound_p (type)) + || variably_modified_type_p (type, NULL_TREE)) { /* For an array, we only need/want a single cleanup region rather than one per element. */ @@ -845,7 +845,7 @@ store_init_value (tree decl, tree init, vec** cleanups, int flags) will perform the dynamic initialization. */ if (value != error_mark_node && (TREE_SIDE_EFFECTS (value) - || array_of_runtime_bound_p (type) + || variably_modified_type_p (type, NULL_TREE) || ! reduced_constant_expression_p (value))) return split_nonconstant_init (decl, value); /* If the value is a constant, just put it in DECL_INITIAL. If DECL diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index a5a8b23..6687d59 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -1638,14 +1638,48 @@ foo (int n) You can use the function @code{alloca} to get an effect much like variable-length arrays. The function @code{alloca} is available in many other C implementations (but not in all). On the other hand, -variable-length arrays are more elegant. +variable-length arrays are available in GCC for all targets and +provide type safety. There are other differences between these two methods. Space allocated with @code{alloca} exists until the containing @emph{function} returns. The space for a variable-length array is deallocated as soon as the array name's scope ends, unless you also use @code{alloca} in this scope. -You can also use variable-length arrays as arguments to functions: +Unlike GCC, G++ instruments variable-length arrays (@xref{Variable Length}) +with checks for erroneous uses: when a variable-length array object is +created its runtime bounds are checked to detect non-positive values, +integer overflows, sizes in excess of SIZE_MAX / 2 bytes, and excess +initializers. When an erroneous variable-length array is detected +the runtime arranges for an exception to be thrown that matches a handler +of type @code{std::bad_array_length}. + +Also unlike GCC, G++ allows variable-length arrays to be initialized. +However, unlike initializer lists for ordinary multidimensional arrays, +those for multidimensional variable-length arrays must be enclosed in +pairs of curly braces delimiting each sequence of values to use to +initialize each subarray. Initializer lists that aren't unambiguously +enclosed in braces are rejected with an error. For example, in the +following function, the initializer list for the ordinary @code{array} +is accepted even though it isn't fully enclosed in braces. The same +initializer list, however, wouldn't be accepted for a multidimensional +variable-length array. To initialize the variable-length array @code{vla}, +the elements of the subarray @code{vla[m]} must be enclosed in braces +as shown. As with ordinary arrays, elements that aren't initialized +explicitly are default-initialized. + +@smallexample +void +foo (int m, int n) +@{ + int array[2][3] = @{ 1, 2, 4, 5, 6 @}; + int vla[m][n] = @{ @{ 1, 2 @}, @{ 4, 5, 6 @} @}; +@} +@end smallexample + + +In C programs (but not in C++) variable-length arrays can also be declared +as function arguments: @smallexample struct entry diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5e047c6..b07b8b2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,17 @@ +2016-04-13 Martin Sebor + + PR c++/69517 + PR c++/70019 + PR c++/70588 + * c-c++-common/ubsan/vla-1.c (main): Catch exceptions. + * g++.dg/cpp1y/vla11.C: New test. + * g++.dg/cpp1y/vla12.C: New test. + * g++.dg/cpp1y/vla13.C: New test. + * g++.dg/cpp1y/vla14.C: New test. + * g++.dg/cpp1y/vla3.C: Restore deleted test. + * gcc/testsuite/g++.dg/init/array24.C: Fully brace VLA initializer. + * g++.dg/ubsan/vla-1.C: Disable exceptions. + 2016-04-13 Jakub Jelinek PR c++/70641 diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c b/gcc/testsuite/c-c++-common/ubsan/vla-1.c index 52ade3a..27ef110 100644 --- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c +++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c @@ -87,18 +87,24 @@ fn12 (void) int main (void) { - fn1 (); - fn2 (); - fn3 (); - fn4 (); - fn5 (); - fn6 (); - fn7 (); - fn8 (); - fn9 (); - fn10 (); - fn11 (); - fn12 (); +#if __cplusplus +# define TRY(stmt) do { try { stmt; } catch (...) { } } while (0) +#else +# define TRY(stmt) stmt +#endif + + TRY (fn1 ()); + TRY (fn2 ()); + TRY (fn3 ()); + TRY (fn4 ()); + TRY (fn5 ()); + TRY (fn6 ()); + TRY (fn7 ()); + TRY (fn8 ()); + TRY (fn9 ()); + TRY (fn10 ()); + TRY (fn11 ()); + TRY (fn12 ()); return 0; } diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C b/gcc/testsuite/g++.dg/cpp1y/vla11.C new file mode 100644 index 0000000..af9624a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C @@ -0,0 +1,711 @@ +// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer +// elements +// PR c++/70019 - VLA size overflow not detected +// +// Runtime test to verify that attempting to either construct a VLA with +// erroneous bounds, or initialize one with an initializer-list that +// contains more elements than the VLA's non-constant (runtime) bounds +// causes an exception to be thrown. Test also verifies that valid +// VLAs and their initializers don't cause such an exception. + +// { dg-do run { target c++11 } } +// { dg-additional-options "-Wno-vla" } + +#pragma GCC diagnostic ignored "-Wvla" + +#define INT_MAX __INT_MAX__ +#define LONG_MAX __LONG_MAX__ +#define SIZE_MAX __SIZE_MAX__ +#define UINT_MAX (~0U) +#define ULONG_MAX (~0LU) + +#define INT_MIN (-__INT_MAX__ - 1) +#define LONG_MIN (-__LONG_MAX__ - 1) + +// The size of the largest allowed VLA in bytes. Bigger objects +// cause an exception to be thrown. Unless the maximum size is +// obscenely large, smaller objects should be successfully created +// provided there's enough stack space. See TEST_NEAR_VLA_MAX_SIZE +// below. +#define MAX (__SIZE_MAX__ / 2) + +// Define to non-zero to exercise very large VLAs with size just +// below the implementation-defined maximum. +#define TEST_NEAR_VLA_MAX_SIZE 0 + +// Define to zero to enable tests that cause an ICE due to c++/58646. +#define BUG_58646 1 + +// Helper macro to make it possible to pass as one multpile arguments +// to another macro. +#define Init(...) __VA_ARGS__ + +typedef __SIZE_TYPE__ size_t; + +// Incremented for each test failure. +int fail; + +// Used to convert a constant array dimension to a non-constant one. +template +T d (T n) +{ + return n; +} + +// Verify either that an expected exception has been thrown or that +// one hasn't been thrown if one isn't expected. +int __attribute__ ((noclone, noinline)) +sink (void *p, int line, bool expect, const char *expr) +{ + if (!p != expect) + { + __builtin_printf ("line %i: Assertion failed: '%s': " + "exception unexpectedly %sthrown\n", + line, expr, !p ? "" : "not "); + ++fail; + } + else + { +#if defined DEBUG && DEBUG + __builtin_printf ("line %i: Assertion passed: '%s': " + "exception %sthrown as expected\n", + line, expr, !p ? "" : "not "); +#endif + } + return 0; +} + +#define _CAT(name, line) name ## line +#define CAT(name, line) _CAT (name, line) + +#define STR(...) #__VA_ARGS__ + +// Type to exercise VLA with. TYPESIZE is the size of the type in bytes. +// Using a template serves two purposes. First, it makes it possible to +// parameterize the test on VLAs of different size. Second, it verifies +// that the checking code can deal with templates (i.e., completes +// the element type of the VLA when necessary). +template +struct alignas (TypeSize) TestType +{ + char data; +}; + +// Test function invoked with a pointer to each test case. Must +// return a value though what value doesn't matter. +int __attribute__ ((noclone, noinline)) +tester (int (*testcase)(const char*), + const char *str, int line, bool expect) +{ + try + { + return testcase (str); + } + catch (...) + { + return sink (0, line, expect, str); + } +} + +// Macro to define a unique specialization of a function template to +// exercise a VLA of type T, rank N, with dimensions given by Dims +// and initializer Init. Expect is true when the VLA initialization +// is expected to trigger an exception. +// The macro creates a unique global dummy int object and initializes +// it with the result of the function. The dummy object servers no +// other purpose but to call the function. The function verifies +// the expected postconditions. +#define TEST(TypeSize, Dims, Init, Expect) \ + static int CAT (testcase, __LINE__)(const char *str) \ + { \ + TestType vla Dims Init; \ + static_assert (sizeof (TestType) == TypeSize, \ + "wrong test type size"); \ + return sink (vla, __LINE__, Expect, str); \ + } \ + const int CAT (dummy, __LINE__) \ + = tester (CAT (testcase, __LINE__), \ + "T<" #TypeSize "> a" #Dims " " STR (Init) ";", \ + __LINE__, Expect) + + +// Create and run a test function exercising a VLA definition +// of one of the following forms: +// TestType VLA Dims; // uninitialized (with Init ()) +// or: +// TestType VLA Dims Init; // initialized (with = Init ({...}) +// +// +-- Element Size (in Bytes) +// | +-- VLA Dimensions (constant as in [3], otherwise d(3)) +// | | +-- VLA Initializer Expression (if any) +// | | | +-- Expect Exception +// | | | | +// V V V V +TEST (1, [d(0)], Init (/* none*/), true); // uninitialized + +#if !BUG_58646 +// The following causes an ICE due to c++/58646. +TEST (1, [d(0)], Init ({}), true); +#endif +TEST (1, [d(0)], Init ({1}), true); // initialized with " {1}" +TEST (1, [d(0)], = Init ({1}), true); // initialized with "= {1}" + +TEST (1, [d(1)], Init (), false); +TEST (1, [d(1)], Init ({}), false); +TEST (1, [d(1)], = Init ({}), false); +TEST (1, [d(1)], Init ({1}), false); +TEST (1, [d(1)], = Init ({1}), false); +TEST (1, [d(1)], Init ({1, 2}), true); +TEST (1, [d(1)], = Init ({1, 2}), true); + +TEST (1, [d(2)], Init (), false); +TEST (1, [d(2)], Init ({}), false); +TEST (1, [d(2)], Init ({1}), false); +TEST (1, [d(2)], Init ({1, 2}), false); +TEST (1, [d(2)], Init ({1, 2, 3}), true); + +#if TEST_NEAR_VLA_MAX_SIZE +// Very large but not erroneous one dimensional VLAs. +TEST (1, [d(MAX)], Init (), false); +TEST (1, [d(MAX)], Init ({}), false); +TEST (1, [d(MAX)], Init ({1}), false); +TEST (1, [d(MAX)], Init ({1, 2}), false); +TEST (1, [d(MAX)], Init ({1, 2, 3}), false); + +TEST ( 2, [d(MAX / 2)], Init (), false); +TEST ( 4, [d(MAX / 4)], Init (), false); +TEST ( 8, [d(MAX / 8)], Init (), false); +TEST (16, [d(MAX / 16)], Init (), false); +TEST (32, [d(MAX / 32)], Init (), false); +TEST (64, [d(MAX / 64)], Init (), false); +#endif // TEST_NEAR_VLA_MAX_SIZE + +// One dimensional VLAs with a negative upper bound. +TEST (1, [d(LONG_MIN)], Init (), true); +TEST (1, [d(INT_MIN)], Init (), true); +TEST (1, [d(-1234)], Init (), true); +TEST (1, [d(-1)], Init (), true); + +// Excessively large one dimensional VLAs. +TEST ( 1, [d(MAX + 1)], Init (), true); +TEST ( 2, [d(MAX)], Init (), true); +TEST ( 4, [d(MAX / 2)], Init (), true); +TEST ( 4, [d(MAX / 3)], Init (), true); +TEST ( 8, [d(MAX / 2)], Init (), true); +TEST ( 8, [d(MAX / 3)], Init (), true); +TEST ( 8, [d(MAX / 4)], Init (), true); +TEST ( 8, [d(MAX / 5)], Init (), true); +TEST ( 8, [d(MAX / 6)], Init (), true); +TEST ( 8, [d(MAX / 7)], Init (), true); +TEST (16, [d(MAX / 15)], Init (), true); +TEST (32, [d(MAX / 31)], Init (), true); +TEST (64, [d(MAX / 63)], Init (), true); +TEST ( 1, [d(SIZE_MAX)], Init (), true); + +TEST (1, [d(LONG_MIN)], Init ({}), true); +TEST (1, [d(INT_MIN)], Init ({}), true); +TEST (1, [d(-1)], Init ({}), true); + +TEST (1, [d(SIZE_MAX)], Init ({}), true); + +TEST (1, [d(LONG_MIN)], Init ({0}), true); +TEST (1, [d(INT_MIN)], Init ({0}), true); +TEST (1, [d(-1)], Init ({0}), true); + +TEST (1, [d(SIZE_MAX)], Init ({0}), true); + +TEST ( 1, [d(SIZE_MAX/2) + 1], Init (), true); +TEST ( 2, [d(SIZE_MAX/4) + 1], Init (), true); +TEST ( 4, [d(SIZE_MAX/8) + 1], Init (), true); +TEST ( 8, [d(SIZE_MAX/16) + 1], Init (), true); +TEST (16, [d(SIZE_MAX/32) + 1], Init (), true); + +TEST ( 1, [d(SIZE_MAX/2) + 1], Init ({1}), true); +TEST ( 2, [d(SIZE_MAX/4) + 1], Init ({1, 2}), true); +TEST ( 4, [d(SIZE_MAX/8) + 1], Init ({1, 2, 3}), true); +TEST ( 8, [d(SIZE_MAX/16) + 1], Init ({1, 2, 3, 4}), true); +TEST (16, [d(SIZE_MAX/32) + 1], Init ({1, 2, 3, 4, 5}), true); + +// Two dimensional VLAs with one constant bound. + +TEST (1, [1][d(0)], Init (), true); + +#if !BUG_58646 +// The following causes an ICE due to c++/58646. +TEST (1, [1][d(0)], Init ({}), true); +#endif +TEST (1, [ ][d(0)], Init ({{1}}), true); // unspecified bound +TEST (1, [1][d(0)], Init ({{1}}), true); + +TEST (1, [1][d(1)], Init (), false); +TEST (1, [1][d(1)], Init ({{1}}), false); +TEST (1, [1][d(1)], Init ({{1, 2}}), true); +TEST (1, [ ][d(1)], Init ({{1, 2}}), true); + +TEST (1, [1][d(2)], Init (), false); +TEST (1, [1][d(2)], Init ({{1}}), false); +TEST (1, [1][d(2)], Init ({{1, 2}}), false); +TEST (1, [ ][d(2)], Init ({{1, 2}}), false); +TEST (1, [1][d(2)], Init ({{1, 2, 3}}), true); +TEST (1, [ ][d(2)], Init ({{1, 2, 3}}), true); + +TEST (1, [2][d(1)], Init (), false); +TEST (1, [2][d(1)], Init ({{1}}), false); +TEST (1, [ ][d(1)], Init ({{1}}), false); +TEST (1, [2][d(1)], Init ({{1}, {2}}), false); +TEST (1, [ ][d(1)], Init ({{1}, {2}}), false); +TEST (1, [2][d(1)], Init ({{1, 2}}), true); +TEST (1, [ ][d(1)], Init ({{1, 2}}), true); +TEST (1, [2][d(1)], Init ({{1}, {2, 3}}), true); +TEST (1, [ ][d(1)], Init ({{1}, {2, 3}}), true); +TEST (1, [2][d(1)], Init ({{1, 2, 3}}), true); +TEST (1, [ ][d(1)], Init ({{1, 2, 3}}), true); +TEST (1, [2][d(1)], Init ({{1, 2, 3}, {4}}), true); +TEST (1, [ ][d(1)], Init ({{1, 2, 3}, {4}}), true); +TEST (1, [2][d(1)], Init ({{1, 2}, {3, 4}}), true); +TEST (1, [ ][d(1)], Init ({{1, 2}, {3, 4}}), true); + +TEST (1, [2][d(2)], Init (), false); +TEST (1, [2][d(2)], Init ({{1}}), false); +TEST (1, [2][d(2)], Init ({{1, 2}}), false); +TEST (1, [2][d(2)], Init ({{1, 2}, {3}}), false); +TEST (1, [2][d(2)], Init ({{1, 2}, {3, 4}}), false); +TEST (1, [2][d(2)], Init ({{1}, {2, 3, 4}}), true); +TEST (1, [2][d(2)], Init ({{1}, {2, 3, 4, 5}}), true); +TEST (1, [2][d(2)], Init ({{1, 2}, {3, 4, 5}}), true); +TEST (1, [2][d(2)], Init ({{1, 2, 3}, {4, 5}}), true); +TEST (1, [2][d(2)], Init ({{1, 2, 3}, {4, 5, 6}}), true); + +TEST (1, [2][d(3)], Init (), false); +TEST (1, [2][d(3)], Init ({{1}}), false); +TEST (1, [2][d(3)], Init ({{1, 2}}), false); +TEST (1, [2][d(3)], Init ({{1, 2}, {3}}), false); +TEST (1, [2][d(3)], Init ({{1, 2}, {3, 4}}), false); +TEST (1, [2][d(3)], Init ({{1}, {2, 3, 4}}), false); +TEST (1, [2][d(3)], Init ({{1}, {2, 3, 4, 5}}), true); +TEST (1, [2][d(3)], Init ({{1, 2}, {3, 4, 5}}), false); +TEST (1, [2][d(3)], Init ({{1, 2, 3}, {4, 5}}), false); +TEST (1, [2][d(3)], Init ({{1, 2, 3}, {4, 5, 6}}), false); +TEST (1, [2][d(3)], Init ({{1, 2, 3}, {4, 5, 6, 7}}), true); +TEST (1, [2][d(3)], Init ({{1, 2, 3, 4}, {5, 6, 7}}), true); +TEST (1, [2][d(3)], Init ({{1, 2, 3, 4, 5}, {6, 7}}), true); +TEST (1, [2][d(3)], Init ({{1, 2, 3, 4, 5, 6}, {7}}), true); +TEST (1, [2][d(3)], Init ({{1, 2, 3, 4, 5, 6, 7}}), true); + +#if TEST_NEAR_VLA_MAX_SIZE +TEST (1, [1][d(MAX)], Init (), false); +# if !BUG_58646 +// The following causes an ICE due to c++/58646. +TEST (1, [1][d(MAX)], Init ({}), false); +# endif +TEST (1, [1][d(MAX)], Init ({{1}}), false); +TEST (1, [1][d(MAX)], Init ({{1, 2}}), false); +TEST (1, [1][d(MAX)], Init ({{1, 2, 3}}), false); +TEST (1, [1][d(MAX)], Init ({{1, 2, 3, 4}}), false); + +TEST (1, [2][d(MAX / 2)], Init (), false); +TEST (1, [2][d(MAX / 2)], Init ({{1}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1, 2}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3, 4}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1}, {2}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1}, {2, 3}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3, 4}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}), false); +TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}), false); +#endif // TEST_NEAR_VLA_MAX_SIZE + +// Excessively large two dimensional VLAs. +TEST (1, [1][d(LONG_MIN)], Init (), true); +TEST (1, [1][d(INT_MIN)], Init (), true); +TEST (1, [1][d(-1)], Init (), true); + +TEST (1, [1][d(SIZE_MAX)], Init (), true); + +#if !BUG_58646 +// The following cause an ICE due to c++/58646. +TEST (1, [1][d(LONG_MIN)], Init ({}), true); +TEST (1, [1][d(INT_MIN)], Init ({}), true); +TEST (1, [1][d(-1)], Init ({}), true); +TEST (1, [1][d(SIZE_MAX)], Init ({}), true); +#endif + +TEST (1, [1][d(LONG_MIN)], Init ({{0}}), true); +TEST (1, [1][d(INT_MIN)], Init ({{0}}), true); +TEST (1, [1][d(-1)], Init ({{0}}), true); +TEST (1, [1][d(SIZE_MAX)], Init ({{0}}), true); + +TEST (1, [d(LONG_MIN)][1], Init (), true); +TEST (1, [d(INT_MIN)][1], Init (), true); +TEST (1, [d(-1)][1], Init (), true); +TEST (1, [d(SIZE_MAX)][1], Init (), true); + +TEST (1, [d(LONG_MIN)][1], Init ({}), true); +TEST (1, [d(INT_MIN)][1], Init ({}), true); +TEST (1, [d(-1)][1], Init ({}), true); +TEST (1, [d(SIZE_MAX)][1], Init ({}), true); + +TEST (1, [d(LONG_MIN)][1], Init ({{0}}), true); +TEST (1, [d(INT_MIN)][1], Init ({{0}}), true); +TEST (1, [d(-1)][1], Init ({{0}}), true); +TEST (1, [d(SIZE_MAX)][1], Init ({{0}}), true); + +// Two dimensional VLAs with no constant bound. +TEST (1, [d(0)][d(0)], Init (), true); +TEST (1, [d(0)][d(0)], Init ({}), true); +#if !BUG_58646 +// The following cause an ICE due to c++/58646. +TEST (1, [d(0)][d(0)], Init ({{}}), true); +TEST (1, [d(0)][d(0)], Init ({{}, {}}), true); +#endif + +TEST (1, [d(0)][d(0)], Init ({{1}}), true); +TEST (1, [d(0)][d(0)], Init ({{1, 2}}), true); +#if !BUG_58646 +TEST (1, [d(0)][d(0)], Init ({{1}, {}}), true); +TEST (1, [d(0)][d(0)], Init ({{}, {1}}), true); +#endif + +TEST (1, [d(1)][d(0)], Init (), true); +TEST (1, [d(1)][d(0)], Init ({}), true); +TEST (1, [d(1)][d(0)], Init ({{1}}), true); + +TEST (1, [d(1)][d(1)], Init (), false); +TEST (1, [d(1)][d(1)], Init ({{1}}), false); +TEST (1, [d(1)][d(1)], Init ({{1, 2}}), true); + +TEST (1, [d(1)][d(2)], Init (), false); +TEST (1, [d(1)][d(2)], Init ({{1}}), false); +TEST (1, [d(1)][d(2)], Init ({{1, 2}}), false); +TEST (1, [d(1)][d(2)], Init ({{1, 2, 3}}), true); + +TEST (1, [d(2)][d(1)], Init (), false); +TEST (1, [d(2)][d(1)], Init ({{1}}), false); +TEST (1, [d(2)][d(1)], Init ({{1}, {2}}), false); +TEST (1, [d(2)][d(1)], Init ({{1, 2}}), true); +TEST (1, [d(2)][d(1)], Init ({{1}, {2, 3}}), true); +TEST (1, [d(2)][d(1)], Init ({{1, 2, 3}}), true); +TEST (1, [d(2)][d(1)], Init ({{1, 2, 3}, {4}}), true); +TEST (1, [d(2)][d(1)], Init ({{1, 2}, {3, 4}}), true); + +TEST (1, [d(2)][d(2)], Init (), false); +TEST (1, [d(2)][d(2)], Init ({{1}}), false); +TEST (1, [d(2)][d(2)], Init ({{1, 2}}), false); +TEST (1, [d(2)][d(2)], Init ({{1, 2}, {3}}), false); +TEST (1, [d(2)][d(2)], Init ({{1, 2}, {3, 4}}), false); +TEST (1, [d(2)][d(2)], Init ({{1}, {2, 3, 4}}), true); +TEST (1, [d(2)][d(2)], Init ({{1}, {2, 3, 4, 5}}), true); +TEST (1, [d(2)][d(2)], Init ({{1, 2}, {3, 4, 5}}), true); +TEST (1, [d(2)][d(2)], Init ({{1, 2, 3}, {4, 5}}), true); +TEST (1, [d(2)][d(2)], Init ({{1, 2, 3}, {4, 5, 6}}), true); + +TEST (1, [d(2)][d(3)], Init (), false); +TEST (1, [d(2)][d(3)], Init ({{1}}), false); +TEST (1, [d(2)][d(3)], Init ({{1, 2}}), false); +TEST (1, [d(2)][d(3)], Init ({{1, 2}, {3}}), false); +TEST (1, [d(2)][d(3)], Init ({{1, 2}, {3, 4}}), false); +TEST (1, [d(2)][d(3)], Init ({{1}, {2, 3, 4}}), false); +TEST (1, [d(2)][d(3)], Init ({{1}, {2, 3, 4, 5}}), true); +TEST (1, [d(2)][d(3)], Init ({{1, 2}, {3, 4, 5}}), false); +TEST (1, [d(2)][d(3)], Init ({{1, 2, 3}, {4, 5}}), false); +TEST (1, [d(2)][d(3)], Init ({{1, 2, 3}, {4, 5, 6}}), false); +TEST (1, [d(2)][d(3)], Init ({{1, 2, 3}, {4, 5, 6, 7}}), true); +TEST (1, [d(2)][d(3)], Init ({{1, 2, 3, 4}, {5, 6, 7}}), true); +TEST (1, [d(2)][d(3)], Init ({{1, 2, 3, 4, 5}, {6, 7}}), true); +TEST (1, [d(2)][d(3)], Init ({{1, 2, 3, 4, 5, 6}, {7}}), true); +TEST (1, [d(2)][d(3)], Init ({{1, 2, 3, 4, 5, 6, 7}}), true); + +#if TEST_NEAR_VLA_MAX_SIZE +TEST (1, [d(1)][d(MAX)], Init (), false); +TEST (1, [d(1)][d(MAX)], Init ({}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1}}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1, 2}}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3}}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4}}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5}}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6}}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7}}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}), false); +TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false); + +TEST (1, [d(2)][d(MAX / 2)], Init (), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2, 3}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3, 4}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}), false); +TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}), false); +#endif + +TEST (1, [d(2)][d(MAX)], Init (), true); +TEST (1, [d(2)][d(MAX)], Init ({{1}}), true); +TEST (1, [d(MAX)][d(MAX)], Init ({{1, 2}}), true); +TEST (1, [d(0)][d(MAX)], Init ({{1}, {2}}), true); +TEST (1, [d(INT_MAX)][d(MAX)], Init ({{1}, {2, 3}}), true); +TEST (1, [d(SIZE_MAX)][d(MAX)], Init ({{1, 2}, {3, 4}, {5}}), true); + +// Erroneous two-dimensional VLAs with size exceeding SIZE_MAX / 2 +// (those must be rejected because no object can be bigger than that, +// otherwise pointer arithmetic breaks). +TEST ( 1, [2][d(SIZE_MAX/2)], Init (), true); +TEST ( 2, [2][d(SIZE_MAX/4)], Init (), true); +TEST ( 4, [2][d(SIZE_MAX/8)], Init (), true); +TEST ( 8, [2][d(SIZE_MAX/16)], Init (), true); +TEST (16, [2][d(SIZE_MAX/32)], Init (), true); + +TEST ( 1, [d(SIZE_MAX/2)][2], Init (), true); +TEST ( 2, [d(SIZE_MAX/4)][2], Init (), true); +TEST ( 4, [d(SIZE_MAX/8)][2], Init (), true); +TEST ( 8, [d(SIZE_MAX/16)][2], Init (), true); +TEST (16, [d(SIZE_MAX/32)][2], Init (), true); + +// Verify that the unspecified bound is factored into the computation +// of the total size. +TEST ( 1, [][d(SIZE_MAX/2)], Init ({{1}, {2}}), true); +TEST ( 2, [][d(SIZE_MAX/4)], Init ({{1}, {2}}), true); +TEST ( 4, [][d(SIZE_MAX/8)], Init ({{1}, {2}}), true); +TEST ( 8, [][d(SIZE_MAX/16)], Init ({{1}, {2}}), true); +TEST (16, [][d(SIZE_MAX/32)], Init ({{1}, {2}}), true); +TEST (16, [][d(SIZE_MAX/64)], Init ({{1}, {2}, {3}}), true); + +// Three dimensional VLAs with two constant bounds. + +TEST (1, [1][1][d(-1)], Init (), true); +TEST (1, [1][1][d(0)], Init (), true); + +#if !BUG_58646 +// The following causes an ICE due to c++/58646. +TEST (1, [1][1][d(0)], Init ({}), true); +TEST (1, [1][1][d(-1)], Init ({{}}), true); +TEST (1, [1][d(-1)][1], Init ({{}}), true); +TEST (1, [d(-1)][1][1], Init ({{}}), true); + +TEST (1, [1][1][d(0)], Init ({{}}), true); +TEST (1, [1][d(0)][1], Init ({{}}), true); +TEST (1, [d(0)][1][1], Init ({{}}), true); +#endif + +TEST (1, [1][1][d(1)], Init (), false); + +#if !BUG_58646 +TEST (1, [1][1][d(1)], Init ({{}}), false); +TEST (1, [1][1][d(1)], Init ({{{}}}), false); +TEST (1, [1][1][d(1)], Init ({{{1}}}), false); +#endif + +TEST (1, [1][1][d(1)], Init ({{{1, 2}}}), true); +TEST (1, [1][1][d(1)], Init ({{{1, 2, 3}}}), true); + +TEST (1, [1][d(1)][1], Init (), false); + +#if !BUG_58646 +TEST (1, [1][d(1)][1], Init ({{}}), false); +TEST (1, [1][d(1)][1], Init ({{{}}}), false); +#endif + +TEST (1, [1][d(1)][1], Init ({{{1}}}), false); +TEST (1, [1][d(1)][1], Init ({{{1}, {2}}}), true); +TEST (1, [1][d(1)][1], Init ({{{1}, {2}, {3}}}), true); + +TEST (1, [d(1)][1][1], Init (), false); + +#if !BUG_58646 +TEST (1, [d(1)][1][1], Init ({{}}), false); +TEST (1, [d(1)][1][1], Init ({{{}}}), false); +#endif + +TEST (1, [d(1)][1][1], Init ({{{1}}}), false); +TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}}), true); +TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true); + +TEST (1, [1][1][d(2)], Init (), false); + +#if !BUG_58646 +TEST (1, [1][1][d(2)], Init ({{}}), false); +TEST (1, [1][1][d(2)], Init ({{{}}}), false); +#endif + +TEST (1, [1][1][d(2)], Init ({{{1}}}), false); +TEST (1, [1][1][d(2)], Init ({{{1, 2}}}), false); +TEST (1, [1][1][d(2)], Init ({{{1, 2, 3}}}), true); + +TEST (1, [1][d(2)][1], Init (), false); + +#if !BUG_58646 +TEST (1, [1][d(2)][1], Init ({{}}), false); +TEST (1, [1][d(2)][1], Init ({{{}}}), false); +#endif +TEST (1, [1][d(2)][1], Init ({{{1}}}), false); +TEST (1, [1][d(2)][1], Init ({{{1}, {2}}}), false); +TEST (1, [1][d(2)][1], Init ({{{1}, {2}, {3}}}), true); + +TEST (1, [d(2)][1][1], Init (), false); + +#if !BUG_58646 +TEST (1, [d(2)][1][1], Init ({{}}), false); +TEST (1, [d(2)][1][1], Init ({{{}}}), false); +#endif +TEST (1, [d(2)][1][1], Init ({{{1}}}), false); +TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}}), false); +TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true); + +TEST (1, [1][2][d(2)], Init (), false); + +#if !BUG_58646 +TEST (1, [1][2][d(2)], Init ({{}}), false); +TEST (1, [1][2][d(2)], Init ({{{}}}), false); +#endif + +TEST (1, [1][2][d(2)], Init ({{{1}}}), false); +TEST (1, [1][2][d(2)], Init ({{{1, 2}}}), false); +TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}}}), true); + +TEST (1, [1][2][d(2)], Init ({{{1}, {2}}}), false); +TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3}}}), false); +TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3}}}), false); +TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3, 4}}}), false); +TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3, 4}}}), true); +TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {}}}), true); +TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {4}}}), true); +TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}}}), true); +TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}), true); +TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true); + +TEST (1, [2][2][d(2)], Init ({{{1}, {2}}}), false); +TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3}}}), false); +TEST (1, [2][2][d(2)], Init ({{{1, 2}}}), false); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3}}}), false); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}}), false); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5}}}), false); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}}}), false); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7}}}), false); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), false); + +TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3, 4}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}), true); +TEST (1, [2][2][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}), true); + +// Three dimensional VLAs with one constant bound. +TEST (1, [2][d(-1)][d(-1)], Init (), true); +TEST (1, [2][d(-1)][d(0)], Init (), true); +TEST (1, [2][d(0)][d(-1)], Init (), true); +TEST (1, [2][d(1)][d(-1)], Init (), true); +TEST (1, [2][d(1)][d(0)], Init (), true); +TEST (1, [2][d(-1)][d(1)], Init (), true); +TEST (1, [2][d(0)][d(1)], Init (), true); + +TEST (1, [2][d(2)][d(2)], Init (), false); +TEST (1, [2][d(2)][d(2)], Init ({{{1}}}), false); +TEST (1, [ ][d(2)][d(2)], Init ({{{1}}}), false); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}}), false); +TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2}}}), false); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}}}), false); +TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3}}}), false); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3}}}), false); +TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3}}}), false); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}), false); +TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}), false); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), false); +TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), false); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}), true); +TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}), true); +TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}), true); +TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}), true); +TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}), true); +TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true); +TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}), true); +TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}, {3}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}), true); +TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}, {5}}}), true); + +#if TEST_NEAR_VLA_MAX_SIZE +// Very large but not erroneous three-dimensional VLAs. +TEST ( 1, [2][d(1)][d(MAX/2)], Init (), false); +TEST ( 2, [2][d(1)][d(MAX/4)], Init (), false); +TEST ( 4, [2][d(1)][d(MAX/8)], Init (), false); +TEST ( 8, [2][d(1)][d(MAX/16)], Init (), false); +TEST (16, [2][d(1)][d(MAX/32)], Init (), false); + +TEST ( 1, [2][d(MAX/2)][d(1)], Init (), false); +TEST ( 2, [2][d(MAX/4)][d(1)], Init (), false); +TEST ( 4, [2][d(MAX/8)][d(1)], Init (), false); +TEST ( 8, [2][d(MAX/16)][d(1)], Init (), false); +TEST (16, [2][d(MAX/32)][d(1)], Init (), false); + +TEST ( 1, [d(MAX/2)][2][d(1)], Init (), false); +TEST ( 2, [d(MAX/4)][2][d(1)], Init (), false); +TEST ( 4, [d(MAX/8)][2][d(1)], Init (), false); +TEST ( 8, [d(MAX/16)][2][d(1)], Init (), false); +TEST (16, [d(MAX/32)][2][d(1)], Init (), false); +#endif // TEST_NEAR_VLA_MAX_SIZE + +// Erroneous three-dimensional VLAs with size exceeding SIZE_MAX / 2 +// (those must be rejected because no object can be bigger than that, +// otherwise pointer arithmetic breaks). +TEST ( 1, [2][d(1)][d(SIZE_MAX/2)], Init (), true); +TEST ( 2, [2][d(1)][d(SIZE_MAX/4)], Init (), true); +TEST ( 4, [2][d(1)][d(SIZE_MAX/8)], Init (), true); +TEST ( 8, [2][d(1)][d(SIZE_MAX/16)], Init (), true); +TEST (16, [2][d(1)][d(SIZE_MAX/32)], Init (), true); + +TEST ( 1, [2][d(SIZE_MAX/2)][d(1)], Init (), true); +TEST ( 2, [2][d(SIZE_MAX/4)][d(1)], Init (), true); +TEST ( 4, [2][d(SIZE_MAX/8)][d(1)], Init (), true); +TEST ( 8, [2][d(SIZE_MAX/16)][d(1)], Init (), true); +TEST (16, [2][d(SIZE_MAX/32)][d(1)], Init (), true); + +TEST ( 1, [d(SIZE_MAX/2)][2][d(1)], Init (), true); +TEST ( 2, [d(SIZE_MAX/4)][2][d(1)], Init (), true); +TEST ( 4, [d(SIZE_MAX/8)][2][d(1)], Init (), true); +TEST ( 8, [d(SIZE_MAX/16)][2][d(1)], Init (), true); +TEST (16, [d(SIZE_MAX/32)][2][d(1)], Init (), true); + +TEST (16, [3][d(SIZE_MAX)][d(SIZE_MAX)], Init (), true); +TEST (32, [d(SIZE_MAX)][5][d(SIZE_MAX)], Init (), true); +TEST (64, [d(SIZE_MAX)][d(SIZE_MAX)][7], Init (), true); + +int main () +{ + if (fail) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/vla12.C b/gcc/testsuite/g++.dg/cpp1y/vla12.C new file mode 100644 index 0000000..f938f3b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/vla12.C @@ -0,0 +1,99 @@ +// Test to verify that variable length arrays the product of whose constant +// bounds overflows or exceeds the implementation-defined limit are diagnosed. +// { dg-do compile { target c++11 } } +// { dg-additional-options "-Wno-error=vla" } + +#define INT_MAX __INT_MAX__ +#define LONG_MAX __LONG_MAX__ +#define SIZE_MAX __SIZE_MAX__ + +typedef __SIZE_TYPE__ size_t; + +#define MAX (SIZE_MAX / 2) + +void test (int x) +{ + const size_t amax = MAX; + + // The following are valid and shouldn't elicit a bounds overflow warning. + { + char a [x][amax]; // { dg-warning "forbids" } + (void)a; + } + + { + char a [amax][x]; // { dg-warning "forbids" } + (void)a; + } + + // The following is invalid and should be diagnosed. Unfortunately, + // when the VLA maximum size is (SIZE_MAX / 2), G++ also issues + // a (bogus) -Woverflow because it computes the array bound in + // a signed type (ssize_t) instead of size_t, in addition to + // rejecting the declaration with error: size of array ‘a’ is too + // large, before the VLA constant bound check has had a chance to + // see it. So the test is disabled. + // { + // char a [x][amax + 1]; + // (void)a; + // } + + { + char a [x][x][amax]; // { dg-warning "forbids" } + (void)a; + } + + { + char a [x][amax][x]; // { dg-warning "forbids" } + (void)a; + } + + { + char a [amax][x][x]; // { dg-warning "forbids" } + (void)a; + } + + { + char a [2][x][amax]; // { dg-warning "forbids|exceeds maximum" } + (void)a; + } + + { + // Unfortunately, the following is rejected with a different error + // earlier during parsing and before the VLA checking gets to see + // it: error: size of array ‘a’ is too large + // Ditto for other multidimensional VLAs where the overflow occurs + // in the computation of the product of adjacent constant bounds. + // char a [x][amax][amax]; + // char b [x][2][amax]; + // That error above also leads to the following error when using + // the variable below. + // error:’ was not declared in this scope + // (void)a; + } + + { + char a [amax][x][amax]; // { dg-warning "forbids|exceeds maximum" } + (void)a; + } + + { + char a [amax][amax][x]; // { dg-warning "forbids|exceeds maximum" } + (void)a; + } + + { + struct A256 { __attribute__ ((aligned (256))) char a; }; + + enum { + M = 1024, + N = MAX / (sizeof (A256) * M) + }; + + A256 a [x][M][x][N]; // { dg-warning "forbids" } + (void)a; + + A256 b [2][x][M][x][N]; // { dg-warning "forbids|exceeds maximum" } + (void)b; + } +} diff --git a/gcc/testsuite/g++.dg/cpp1y/vla13.C b/gcc/testsuite/g++.dg/cpp1y/vla13.C new file mode 100644 index 0000000..d473a63 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/vla13.C @@ -0,0 +1,260 @@ +// PR c++/70019 - VLA size overflow not detected +// Runtime test to verify that attempting to initialize a VLA with a string +// or character array that's longer than the non-constant (runtime) bound +// of the VLA causes an exception to be thrown. For a compile-time version +// of the test see vla14.C. + +// { dg-do run { target c++11 } } +// { dg-additional-options "-Wno-vla" } + +#pragma GCC diagnostic ignored "-Wvla" + +#define SIZE_MAX __SIZE_MAX__ + +// The size of the largest allowed VLA in bytes. Bigger objects +// cause an exception to be thrown. Unless the maximum size is +// obscenely large, smaller objects should be successfully created +// provided there's enough stack space. See TEST_NEAR_VLA_MAX_SIZE +// below. +#define MAX (__SIZE_MAX__ / 2) + +// Define to non-zero to exercise very large VLAs with size just +// below the implementation-defined maximum. +#define TEST_NEAR_VLA_MAX_SIZE 0 + +// Define to zero to enable tests that cause an ICE due to c++/58646. +#define BUG_58646 1 + +// Define to zero to enable tests that cause an ICE due to c++/69487. +#define BUG_69487 1 + +// Helper macro to make it possible to pass as one multpile arguments +// to another macro. +#define Init(...) __VA_ARGS__ + +typedef __SIZE_TYPE__ size_t; + +// Incremented for each test failure. +int fail; + +// Used to convert a constant array dimension to a non-constant one. +template +T d (T n) +{ + return n; +} + +// Verify either that an expected exception has been thrown or that +// one hasn't been thrown if one isn't expected. +int __attribute__ ((noclone, noinline)) +sink (void *p, int line, bool expect, const char *expr) +{ + if (!p != expect) + { + __builtin_printf ("line %i: Assertion failed: '%s': " + "exception unexpectedly %sthrown\n", + line, expr, !p ? "" : "not "); + ++fail; + } + else + { +#if defined DEBUG && DEBUG + __builtin_printf ("line %i: Assertion passed: '%s': " + "exception %sthrown as expected\n", + line, expr, !p ? "" : "not "); +#endif + } + return 0; +} + +template +int test (); + +#define _CAT(name, line) name ## line +#define CAT(name, line) _CAT (name, line) + +#define STR(...) #__VA_ARGS__ + +// Macro to define a unique specialization of a function template to +// exercise a VLA of type T, rank N, with dimensions given by Dims +// and initializer Init. Expect is true when the VLA initialization +// is expected to trigger an exception. +// The macro creates a unique global dummy int object and initializes +// it with the result of the function. The dummy object servers no +// other purpose but to call the function. The function verifies +// the expected postconditions. +#define TEST(T, Dims, Init, Expect) \ + template <> \ + int test() \ + { \ + const char str[] = "char a" #Dims " = { " STR (Init) " }"; \ + try { \ + T a Dims = { Init }; \ + return sink (a, __LINE__, Expect, str); \ + } \ + catch (...) { \ + return sink (0, __LINE__, Expect, str); \ + } \ + } \ + const int CAT (dummy, __LINE__) = test() + + +// Create and run a test function exercising a VLA definition +// +-- Element Type +// | +-- VLA Dimensions +// | | +-- VLA Initializer +// | | | +// | | | +-- Expect Exception +// | | | | +// V V V V +TEST (char, [d(-1)], "", true); + +TEST (char, [d(0)], "", true); +TEST (char, [d(0)], (""), true); + +TEST (char, [d(1)], "", false); +TEST (char, [d(1)], (""), false); + +TEST (char, [d(1)], "1", true); +TEST (char, [d(1)], ("1"), true); + +TEST (char, [d(1)], "12", true); +TEST (char, [d(1)], "1234567890", true); + +TEST (char, [d(2)], "", false); +TEST (char, [d(2)], (""), false); + +TEST (char, [d(2)], "1", false); +TEST (char, [d(2)], "12", true); +TEST (char, [d(2)], "123", true); +TEST (char, [d(2)], "1234567890", true); + +TEST (char, [d(3)], "", false); +TEST (char, [d(3)], "1", false); +TEST (char, [d(3)], "12", false); +TEST (char, [d(3)], "123", true); +TEST (char, [d(3)], "1234", true); +TEST (char, [d(3)], "1234567890", true); + +#if TEST_NEAR_VLA_MAX_SIZE + +# if !BUG_69487 +// The following crash due to c++/69487. +TEST (char, [d(MAX)], "", false); +TEST (char, [d(MAX)], "1", false); +TEST (char, [d(MAX)], "12", false); +TEST (char, [d(MAX)], "1234567890", false); +# endif + +TEST (char, [d(MAX)], Init (), false); +TEST (char, [d(MAX)], Init (1), false); +TEST (char, [d(MAX)], Init (1, 2), false); +TEST (char, [d(MAX)], Init (1, 2, 3, 4, 5, 6, 7, 8, 9, 0), false); +#endif + +TEST (char, [d(SIZE_MAX / 2 + 1)], "", true); +TEST (char, [d(SIZE_MAX - 2)], "", true); +TEST (char, [d(SIZE_MAX - 1)], "", true); + +TEST (wchar_t, [d(1)], L"", false); +TEST (wchar_t, [d(1)], (L""), false); +TEST (wchar_t, [d(1)], L"1", true); +TEST (wchar_t, [d(1)], L"12", true); +TEST (wchar_t, [d(1)], L"1234567890", true); + +TEST (wchar_t, [d(2)], L"", false); +TEST (wchar_t, [d(2)], L"1", false); +TEST (wchar_t, [d(2)], L"12", true); +TEST (wchar_t, [d(2)], L"123", true); +TEST (wchar_t, [d(2)], L"1234567890", true); + +TEST (char, [d(1)][d(1)], Init (""), false); +TEST (char, [1] [d(1)], Init (""), false); +TEST (char, [d(1)][1], Init (""), false); + +TEST (char, [d(1)][d(1)], Init ("1"), true); + +// The following is accepted at compile time but throws an exception +// at runtime since in C++ a one-element array cannot be initialized +// with a string literal of length one because there isn't room for +// the terminating NUL +TEST (char, [1][d(1)], Init ("1"), true); + +// The following is rejected at compile-time since a one-element array +// cannot be initialized with a string literal of length one because +// there isn't room for the terminating NUL (see vla14.C). +// TEST (char, [d(1)][1], Init ("1"), false); + +TEST (char, [d(1)][d(1)], Init ("12"), true); +TEST (char, [d(1)][d(1)], Init ("1", "2"), true); +TEST (char, [d(1)][d(1)], Init ("1", "23"), true); + +TEST (char, [d(2)][d(2)], Init ("", ""), false); +TEST (char, [d(2)][d(2)], Init ("", "1"), false); +TEST (char, [d(2)][d(2)], Init ("1", ""), false); +TEST (char, [d(2)][d(2)], Init ("1", "1"), false); +TEST (char, [2][d(2)], Init ("", "1"), false); +TEST (char, [2][d(2)], Init ("1", ""), false); +TEST (char, [2][d(2)], Init ("1", "1"), false); +TEST (char, [d(2)][2], Init ("", "1"), false); +TEST (char, [d(2)][2], Init ("1", ""), false); +TEST (char, [d(2)][2], Init ("1", "1"), false); + +TEST (char, [2][d(2)], Init ("1", "23"), true); +TEST (char, [d(2)][d(2)], Init ("1", "23"), true); +TEST (char, [d(2)][d(2)], Init ("1", "23"), true); +TEST (char, [d(2)][d(2)], Init ("12","3"), true); + +#if TEST_NEAR_VLA_MAX_SIZE +# if !BUG_69487 + // The following crash due to c++/69487. +TEST (char, [1][d(MAX)], Init (""), false); +TEST (char, [1][d(MAX)], Init ("1"), false); +TEST (char, [1][d(MAX)], Init ("12"), false); +TEST (char, [1][d(MAX)], Init ("1234567890"), false); +# endif + +# if !BUG_58646 +// The following causes an ICE due to c++/58646. +TEST (char, [1][d(MAX)], Init (), false); +# endif + +TEST (char, [1][d(MAX)], Init ({1}), false); +TEST (char, [1][d(MAX)], Init ({1, 2}), false); +TEST (char, [1][d(MAX)], Init ({1, 2, 3}), false); +TEST (char, [1][d(MAX)], Init ({1, 2, 3, 4, 5, 6, 7, 8, 9, 0}), false); + +TEST (char, [d(MAX)][1], Init ({1}), false); +TEST (char, [d(MAX)][1], Init ({1}, {2}), false); +TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}), false); +TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}, {4}, {5}, + {6}, {7}, {8}, {9}, {0}), false); +#endif // TEST_NEAR_VLA_MAX_SIZE + +// The following are expected to throw due to excessive size. +TEST (char, [2][d(MAX)], Init ({1}), true); +TEST (char, [2][d(MAX)], Init ({1, 2}), true); +TEST (char, [2][d(MAX)], Init ({1}, {2}), true); +TEST (char, [2][d(MAX)], Init ({1, 2}, {3, 4}), true); +TEST (char, [2][d(MAX)], Init ({1, 2, 3}, {4, 5, 6}), true); +TEST (char, [2][d(MAX)], Init ({1, 2, 3, 4}, {5, 6, 7, 8}), true); + +TEST (char, [d(MAX)][2], Init ({1}), true); +TEST (char, [d(MAX)][2], Init ({1, 2}), true); +TEST (char, [d(MAX)][2], Init ({1}, {2}), true); +TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}), true); +TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}), true); +TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}), true); + +TEST (char, [d(MAX)][d(MAX)], Init ({1}), true); +TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}), true); +TEST (char, [d(MAX)][d(MAX)], Init ({1}, {2}), true); +TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}), true); +TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}), true); +TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}), true); + +int main () +{ + if (fail) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/vla14.C b/gcc/testsuite/g++.dg/cpp1y/vla14.C new file mode 100644 index 0000000..4a0e827 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/vla14.C @@ -0,0 +1,48 @@ +// PR c++/70019 - VLA size overflow not detected +// Compile-time test to verify that attempting to initialize a VLA with +// a string that's longer than the VLA's constant bound is diagnosed at +// compile time. For a runtime version of the test see vla13.C. + +// { dg-do run } +// { dg-additional-options "-Wno-vla" } + + +void test (int n) +{ + char a1[n][1] = { { "a" } }; // { dg-error "initializer-string for array of chars is too long" } + (void)a1; + + char a2[1][n] = { { "a" } }; + (void)a2; + + char a3[n][1][1] = { { { "a" } } }; // { dg-error "initializer-string for array of chars is too long" } + (void)a3; + + char a4[1][1][n] = { { { "a" } } }; + (void)a4; + + char a5[1][n][1] = { { { "a" } } }; // { dg-error "initializer-string for array of chars is too long" } + (void)a5; + + char a6[n][1][n] = { { { "a" } } }; + (void)a6; + + + wchar_t a7[n][1] = { { L"a" } }; // { dg-error "initializer-string for array of chars is too long" } + (void)a7; + + wchar_t a8[1][n] = { { L"a" } }; + (void)a8; + + wchar_t a9[n][1][1] = { { { L"a" } } }; // { dg-error "initializer-string for array of chars is too long" } + (void)a9; + + wchar_t a10[1][1][n] = { { { L"a" } } }; + (void)a10; + + wchar_t a11[][n][1] = { { { L"a" } } }; // { dg-error "initializer-string for array of chars is too long" } + (void)a11; + + wchar_t a12[n][1][n] = { { { L"a" } } }; + (void)a12; +} diff --git a/gcc/testsuite/g++.dg/cpp1y/vla3.C b/gcc/testsuite/g++.dg/cpp1y/vla3.C new file mode 100644 index 0000000..9b2d6b307 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/vla3.C @@ -0,0 +1,43 @@ +// Test for throwing bad_array_length on invalid array length. +// { dg-do run { target c++14 } } +// { dg-additional-options "-Wno-vla" } + +namespace std +{ +struct exception +{ + virtual ~exception (); + virtual const char* what () const throw (); +}; +} + +int f(int i) +{ + int ar[i]{1,2,3,4}; + return ar[i-1]; +} + +void g(int i) +{ + int ar[i]; + ar[0] = 42; +} + +int main() +{ + int ok = 0; + f(4); // OK + try { + f(3); // too small + } + catch (std::exception &e) { + ++ok; + } + try { g(-24); } // negative + catch (std::exception &e) { + ++ok; + } + + if (ok != 2) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/init/array24.C b/gcc/testsuite/g++.dg/init/array24.C index 2d72df4..fc10c0a 100644 --- a/gcc/testsuite/g++.dg/init/array24.C +++ b/gcc/testsuite/g++.dg/init/array24.C @@ -3,5 +3,5 @@ void foo(int i) { - int x[][i] = { 0 }; + int x[][i] = { { 0 } }; } diff --git a/gcc/testsuite/g++.dg/ubsan/vla-1.C b/gcc/testsuite/g++.dg/ubsan/vla-1.C index 311cdb1..374c80a 100644 --- a/gcc/testsuite/g++.dg/ubsan/vla-1.C +++ b/gcc/testsuite/g++.dg/ubsan/vla-1.C @@ -1,5 +1,8 @@ // { dg-do run } -// { dg-options "-Wno-vla -fsanitize=undefined" } +// Disable exceptions to prevent the erroneous initializer from +// throwing before the sanitizer instrumentation has detected +// the problem. +// { dg-options "-Wno-vla -fno-exceptions -fsanitize=undefined" } // { dg-output "index 1 out of bounds" } void f(int i) { diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 2abb015..d31a5d2 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,9 @@ +2016-04-13 Martin Sebor + + PR c++/69517 + * testsuite/25_algorithms/rotate/moveable2.cc: Make sure VLA + upper bound is positive. + 2016-04-13 Jonathan Wakely * include/bits/c++config (_GLIBCXX_BEGIN_NAMESPACE_EMPTY_TYPES, diff --git a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc index d9d1f2a..f944236 100644 --- a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc +++ b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc @@ -44,7 +44,8 @@ template { bool test __attribute__((unused)) = true; - rvalstruct array[length]; + /* Make sure the VLA upper bound is positive. */ + rvalstruct array[length + 1]; for(int i = 0; i < length; ++i) array[i] = i; Con con(array, array + length); -- 2.7.4