From 5a68fae797b88216b40eb6af8c75dec6e98b983c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 3 Apr 2017 17:15:36 -0400 Subject: [PATCH] PR sanitizer/79993 - ICE with VLA initialization from string PR c++/69487 - wrong VLA initialization from string * init.c (finish_length_check): Split out from build_vec_init. (build_vec_init): Handle STRING_CST. * typeck2.c (split_nonconstant_init): Handle STRING_CST. (digest_init_r): Don't give a STRING_CST VLA type. From-SVN: r246662 --- gcc/cp/ChangeLog | 9 +++ gcc/cp/init.c | 92 ++++++++++++++++++++--------- gcc/cp/typeck2.c | 7 ++- gcc/testsuite/g++.dg/asan/pr78201.C | 13 ++++ gcc/testsuite/g++.dg/ext/vla17.C | 15 +++++ 5 files changed, 108 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/g++.dg/asan/pr78201.C create mode 100644 gcc/testsuite/g++.dg/ext/vla17.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 743847908d0..f3c668b870d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2017-04-03 Jason Merrill + + PR sanitizer/79993 - ICE with VLA initialization from string + PR c++/69487 - wrong VLA initialization from string + * init.c (finish_length_check): Split out from build_vec_init. + (build_vec_init): Handle STRING_CST. + * typeck2.c (split_nonconstant_init): Handle STRING_CST. + (digest_init_r): Don't give a STRING_CST VLA type. + 2017-03-31 Jakub Jelinek PR c++/79572 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 773279504ee..2015205efd6 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3884,6 +3884,35 @@ vec_copy_assign_is_trivial (tree inner_elt_type, tree init) return is_trivially_xible (MODIFY_EXPR, inner_elt_type, fromtype); } +/* Subroutine of build_vec_init: Check that the array has at least N + elements. Other parameters are local variables in build_vec_init. */ + +void +finish_length_check (tree atype, tree iterator, tree obase, unsigned n) +{ + tree nelts = build_int_cst (ptrdiff_type_node, n - 1); + if (TREE_CODE (atype) != ARRAY_TYPE) + { + if (flag_exceptions) + { + tree c = fold_build2 (LT_EXPR, boolean_type_node, iterator, + nelts); + c = build3 (COND_EXPR, void_type_node, c, + throw_bad_array_new_length (), void_node); + finish_expr_stmt (c); + } + /* Don't check an array new when -fno-exceptions. */ + } + else if (flag_sanitize & SANITIZE_BOUNDS + && do_ubsan_in_current_function ()) + { + /* Make sure the last element of the initializer is in bounds. */ + finish_expr_stmt + (ubsan_instrument_bounds + (input_location, obase, &nelts, /*ignore_off_by_one*/false)); + } +} + /* `build_vec_init' returns tree structure that performs initialization of a vector of aggregate types. @@ -3932,6 +3961,8 @@ build_vec_init (tree base, tree maxindex, tree init, tree obase = base; bool xvalue = false; bool errors = false; + location_t loc = (init ? EXPR_LOC_OR_LOC (init, input_location) + : location_of (base)); if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype)) maxindex = array_type_nelts (atype); @@ -3963,10 +3994,12 @@ build_vec_init (tree base, tree maxindex, tree init, } } - /* If we have a braced-init-list, make sure that the array + /* If we have a braced-init-list or string constant, make sure that the array is big enough for all the initializers. */ - bool length_check = (init && TREE_CODE (init) == CONSTRUCTOR - && CONSTRUCTOR_NELTS (init) > 0 + bool length_check = (init + && (TREE_CODE (init) == STRING_CST + || (TREE_CODE (init) == CONSTRUCTOR + && CONSTRUCTOR_NELTS (init) > 0)) && !TREE_CONSTANT (maxindex)); if (init @@ -4105,30 +4138,7 @@ build_vec_init (tree base, tree maxindex, tree init, from_array = 0; if (length_check) - { - tree nelts = build_int_cst (ptrdiff_type_node, - CONSTRUCTOR_NELTS (init) - 1); - if (TREE_CODE (atype) != ARRAY_TYPE) - { - if (flag_exceptions) - { - tree c = fold_build2 (LT_EXPR, boolean_type_node, iterator, - nelts); - c = build3 (COND_EXPR, void_type_node, c, - throw_bad_array_new_length (), void_node); - finish_expr_stmt (c); - } - /* Don't check an array new when -fno-exceptions. */ - } - else if (flag_sanitize & SANITIZE_BOUNDS - && do_ubsan_in_current_function ()) - { - /* Make sure the last element of the initializer is in bounds. */ - finish_expr_stmt - (ubsan_instrument_bounds - (input_location, obase, &nelts, /*ignore_off_by_one*/false)); - } - } + finish_length_check (atype, iterator, obase, CONSTRUCTOR_NELTS (init)); if (try_const) vec_alloc (const_vec, CONSTRUCTOR_NELTS (init)); @@ -4196,6 +4206,34 @@ build_vec_init (tree base, tree maxindex, tree init, /* Any elements without explicit initializers get T{}. */ empty_list = true; } + else if (init && TREE_CODE (init) == STRING_CST) + { + /* Check that the array is at least as long as the string. */ + if (length_check) + finish_length_check (atype, iterator, obase, + TREE_STRING_LENGTH (init)); + tree length = build_int_cst (ptrdiff_type_node, + TREE_STRING_LENGTH (init)); + + /* Copy the string to the first part of the array. */ + tree alias_set = build_int_cst (build_pointer_type (type), 0); + tree lhs = build2 (MEM_REF, TREE_TYPE (init), base, alias_set); + tree stmt = build2 (MODIFY_EXPR, void_type_node, lhs, init); + finish_expr_stmt (stmt); + + /* Adjust the counter and pointer. */ + stmt = cp_build_binary_op (loc, MINUS_EXPR, iterator, length, complain); + stmt = build2 (MODIFY_EXPR, void_type_node, iterator, stmt); + finish_expr_stmt (stmt); + + stmt = cp_build_binary_op (loc, PLUS_EXPR, base, length, complain); + stmt = build2 (MODIFY_EXPR, void_type_node, base, stmt); + finish_expr_stmt (stmt); + + /* And set the rest of the array to NUL. */ + from_array = 0; + explicit_value_init_p = true; + } else if (from_array) { if (init) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 58a01c98f2a..d1a393059a4 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -749,6 +749,10 @@ split_nonconstant_init (tree dest, tree init) DECL_INITIAL (dest) = init; TREE_READONLY (dest) = 0; } + else if (TREE_CODE (init) == STRING_CST + && array_of_runtime_bound_p (TREE_TYPE (dest))) + code = build_vec_init (dest, NULL_TREE, init, /*value-init*/false, + /*from array*/1, tf_warning_or_error); else code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init); @@ -1066,7 +1070,8 @@ digest_init_r (tree type, tree init, bool nested, int flags, } } - if (type != TREE_TYPE (init)) + if (type != TREE_TYPE (init) + && !variably_modified_type_p (type, NULL_TREE)) { init = copy_node (init); TREE_TYPE (init) = type; diff --git a/gcc/testsuite/g++.dg/asan/pr78201.C b/gcc/testsuite/g++.dg/asan/pr78201.C new file mode 100644 index 00000000000..931ef44a966 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/pr78201.C @@ -0,0 +1,13 @@ +// PR middle-end/78201 +// { dg-do compile } +// { dg-options "-O2 -fsanitize=address" } + +struct B { long d (); } *c; +long e; + +void +foo () +{ + char a[e] = ""; + c && c->d(); +} diff --git a/gcc/testsuite/g++.dg/ext/vla17.C b/gcc/testsuite/g++.dg/ext/vla17.C new file mode 100644 index 00000000000..431167cb48e --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/vla17.C @@ -0,0 +1,15 @@ +// PR c++/69487 +// { dg-do run } +// { dg-options -Wno-vla } + +int size = 6; + +int main() +{ + char buffer[size] = ""; + for (int i = 0; i != size; ++i) + { + if (buffer[i] != 0) + __builtin_abort(); + } +} -- 2.30.2