From 46621807e9bf7bc94302cda27852e33a3c766112 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 8 Jan 2015 15:58:39 -0500 Subject: [PATCH] init.c (build_vec_init): Call ubsan_instrument_bounds to check whether an initializer-list is too big... * init.c (build_vec_init): Call ubsan_instrument_bounds to check whether an initializer-list is too big for a VLA. (throw_bad_array_length): Remove. * cp-tree.h: Remove prototype. From-SVN: r219359 --- gcc/cp/ChangeLog | 7 ++++ gcc/cp/cp-tree.h | 1 - gcc/cp/init.c | 58 +++++++++++++++--------------- gcc/doc/invoke.texi | 4 +-- gcc/testsuite/g++.dg/ubsan/vla-1.C | 13 +++++++ 5 files changed, 49 insertions(+), 34 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ubsan/vla-1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5c576bc262b..46d795705d9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2015-01-08 Jason Merrill + + * init.c (build_vec_init): Call ubsan_instrument_bounds to check + whether an initializer-list is too big for a VLA. + (throw_bad_array_length): Remove. + * cp-tree.h: Remove prototype. + 2015-01-08 Paolo Carlini PR c++/60753 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2afa531adda..77f2b5b918c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5574,7 +5574,6 @@ extern tree get_nsdmi (tree, bool); extern tree build_offset_ref (tree, tree, bool, tsubst_flags_t); extern tree throw_bad_array_new_length (void); -extern tree throw_bad_array_length (void); extern tree build_new (vec **, tree, tree, vec **, int, tsubst_flags_t); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index a5ac11c3a0f..6f324926aef 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "gimplify.h" #include "wide-int.h" +#include "c-family/c-ubsan.h" static bool begin_init_stmts (tree *, tree *); static tree finish_init_stmts (bool, tree, tree); @@ -2241,20 +2242,6 @@ throw_bad_array_new_length (void) return build_cxx_call (fn, 0, NULL, tf_warning_or_error); } -/* Call __cxa_bad_array_length to indicate that there were too many - initializers. */ - -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); -} - /* 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 @@ -3419,7 +3406,6 @@ build_vec_init (tree base, tree maxindex, tree init, tree obase = base; bool xvalue = false; bool errors = false; - tree length_check = NULL_TREE; if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype)) maxindex = array_type_nelts (atype); @@ -3440,12 +3426,9 @@ build_vec_init (tree base, tree maxindex, tree init, /* If we have a braced-init-list, make sure that the array is big enough for all the initializers. */ - if (init && TREE_CODE (init) == CONSTRUCTOR - && CONSTRUCTOR_NELTS (init) > 0 - && !TREE_CONSTANT (maxindex) - && flag_exceptions) - length_check = fold_build2 (LT_EXPR, boolean_type_node, maxindex, - size_int (CONSTRUCTOR_NELTS (init) - 1)); + bool length_check = (init && TREE_CODE (init) == CONSTRUCTOR + && CONSTRUCTOR_NELTS (init) > 0 + && !TREE_CONSTANT (maxindex)); if (init && TREE_CODE (atype) == ARRAY_TYPE @@ -3468,10 +3451,6 @@ build_vec_init (tree base, tree maxindex, tree init, if (BRACE_ENCLOSED_INITIALIZER_P (init)) init = digest_init (atype, init, complain); stmt_expr = build2 (INIT_EXPR, atype, base, init); - if (length_check) - stmt_expr = build3 (COND_EXPR, atype, length_check, - throw_bad_array_length (), - stmt_expr); return stmt_expr; } @@ -3582,11 +3561,30 @@ build_vec_init (tree base, tree maxindex, tree init, if (length_check) { - tree throw_call; - throw_call = throw_bad_array_new_length (); - length_check = build3 (COND_EXPR, void_type_node, length_check, - throw_call, void_node); - finish_expr_stmt (length_check); + tree nelts = size_int (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 + && current_function_decl + && !lookup_attribute ("no_sanitize_undefined", + DECL_ATTRIBUTES + (current_function_decl))) + { + /* 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)); + } } if (try_const) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 817312741c6..2d06396b241 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -5629,9 +5629,7 @@ call into a diagnostics message call instead. When reaching the @item -fsanitize=vla-bound @opindex fsanitize=vla-bound This option instructs the compiler to check that the size of a variable -length array is positive. This option does not have any effect in -@option{-std=c++14} mode, as the standard requires the exception be thrown -instead. +length array is positive. @item -fsanitize=null @opindex fsanitize=null diff --git a/gcc/testsuite/g++.dg/ubsan/vla-1.C b/gcc/testsuite/g++.dg/ubsan/vla-1.C new file mode 100644 index 00000000000..e7f24945f7a --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/vla-1.C @@ -0,0 +1,13 @@ +// { dg-do run } +// { dg-options "-Wno-vla -fsanitize=undefined" } +// { dg-shouldfail "ubsan" } +// { dg-output "index 1 out of bounds" } + +void f(int i) { + int ar[i] = { 42, 24 }; +} + +int main() +{ + f(1); +} -- 2.30.2