From 7d5e76c8de1b6c4b2ae5576ab909dc9e580b216b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 8 May 2013 23:58:00 -0400 Subject: [PATCH] Core 624/N2932: Throw bad_array_new_length on overflow in array new size calculation. libstdc++-v3/ * libsupc++/new: Add std::bad_array_new_length. * libsupc++/bad_array_new.cc: New. * libsupc++/eh_aux_runtime.cc: Add __cxa_throw_bad_array_new_length. * libsupc++/Makefile.in: Build them. * config/abi/pre/gnu.ver: Add new symbols. * config/abi/pre/gnu-versioned-namespace.ver: Add new symbols. gcc/cp/ * init.c (throw_bad_array_new_length): New. (build_new_1): Use it. Don't warn about braced-init-list. (build_vec_init): Use it. * call.c (build_operator_new_call): Use it. From-SVN: r198731 --- gcc/cp/ChangeLog | 6 +++ gcc/cp/call.c | 9 ++++- gcc/cp/cp-tree.h | 1 + gcc/cp/init.c | 46 ++++++++++++++++++---- gcc/testsuite/g++.dg/cpp0x/bad_array_new1.C | 20 ++++++++++ gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C | 21 ++++++++++ gcc/testsuite/g++.dg/cpp0x/initlist21.C | 1 - gcc/testsuite/g++.dg/init/new40.C | 2 + libstdc++-v3/ChangeLog | 10 +++++ .../config/abi/pre/gnu-versioned-namespace.ver | 3 ++ libstdc++-v3/config/abi/pre/gnu.ver | 4 ++ libstdc++-v3/libsupc++/Makefile.in | 14 ++++++- libstdc++-v3/libsupc++/bad_array_new.cc | 36 +++++++++++++++++ libstdc++-v3/libsupc++/cxxabi.h | 3 ++ libstdc++-v3/libsupc++/eh_aux_runtime.cc | 4 ++ libstdc++-v3/libsupc++/new | 15 +++++++ 16 files changed, 184 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/bad_array_new1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C create mode 100644 libstdc++-v3/libsupc++/bad_array_new.cc diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 560b463..c2ce5d9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2013-05-08 Jason Merrill + Core 624/N2932 + * init.c (throw_bad_array_new_length): New. + (build_new_1): Use it. Don't warn about braced-init-list. + (build_vec_init): Use it. + * call.c (build_operator_new_call): Use it. + PR c++/57068 * decl.c (grokdeclarator): Warn about ref-qualifiers here. * parser.c (cp_parser_ref_qualifier_seq_opt): Not here. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 88bf100..bd8f531 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3951,8 +3951,13 @@ build_operator_new_call (tree fnname, vec **args, *fn = NULL_TREE; /* Set to (size_t)-1 if the size check fails. */ if (size_check != NULL_TREE) - *size = fold_build3 (COND_EXPR, sizetype, size_check, - original_size, TYPE_MAX_VALUE (sizetype)); + { + tree errval = TYPE_MAX_VALUE (sizetype); + if (cxx_dialect >= cxx11) + errval = throw_bad_array_new_length (); + *size = fold_build3 (COND_EXPR, sizetype, size_check, + original_size, errval); + } vec_safe_insert (*args, 0, *size); *args = resolve_args (*args, complain); if (*args == NULL) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 78fd56b..dec7390 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5357,6 +5357,7 @@ extern tree build_value_init (tree, tsubst_flags_t); extern tree build_value_init_noctor (tree, tsubst_flags_t); extern tree build_offset_ref (tree, tree, bool, tsubst_flags_t); +extern tree throw_bad_array_new_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 3587b08..765c471 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2170,6 +2170,21 @@ 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_bad_array_new_length to indicate that the size calculation + overflowed. Pretend it returns sizetype so that it plays nicely in the + COND_EXPR. */ + +tree +throw_bad_array_new_length (void) +{ + tree fn = get_identifier ("__cxa_throw_bad_array_new_length"); + if (!get_global_value_if_present (fn, &fn)) + fn = push_throw_library_fn (fn, build_function_type_list (sizetype, + 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 @@ -2472,9 +2487,12 @@ build_new_1 (vec **placement, tree type, tree nelts, outer_nelts_check = NULL_TREE; } /* Perform the overflow check. */ + tree errval = TYPE_MAX_VALUE (sizetype); + if (cxx_dialect >= cxx11) + errval = throw_bad_array_new_length (); if (outer_nelts_check != NULL_TREE) size = fold_build3 (COND_EXPR, sizetype, outer_nelts_check, - size, TYPE_MAX_VALUE (sizetype)); + size, errval); /* Create the argument list. */ vec_safe_insert (*placement, 0, size); /* Do name-lookup to find the appropriate operator. */ @@ -2699,12 +2717,8 @@ build_new_1 (vec **placement, tree type, tree nelts, domain = compute_array_index_type (NULL_TREE, nelts, complain); else - { - domain = NULL_TREE; - if (CONSTRUCTOR_NELTS (vecinit) > 0) - warning (0, "non-constant array size in new, unable " - "to verify length of initializer-list"); - } + /* We'll check the length at runtime. */ + domain = NULL_TREE; arraytype = build_cplus_array_type (type, domain); vecinit = digest_init (arraytype, vecinit, complain); } @@ -3291,6 +3305,7 @@ 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); @@ -3309,6 +3324,14 @@ build_vec_init (tree base, tree maxindex, tree init, && from_array != 2) init = TARGET_EXPR_INITIAL (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)) + length_check = fold_build2 (LT_EXPR, boolean_type_node, maxindex, + size_int (CONSTRUCTOR_NELTS (init) - 1)); + if (init && TREE_CODE (atype) == ARRAY_TYPE && (from_array == 2 @@ -3441,6 +3464,15 @@ build_vec_init (tree base, tree maxindex, tree init, vec *new_vec; from_array = 0; + 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_zero_node); + finish_expr_stmt (length_check); + } + if (try_const) vec_alloc (new_vec, CONSTRUCTOR_NELTS (init)); else diff --git a/gcc/testsuite/g++.dg/cpp0x/bad_array_new1.C b/gcc/testsuite/g++.dg/cpp0x/bad_array_new1.C new file mode 100644 index 0000000..cd5f0c8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/bad_array_new1.C @@ -0,0 +1,20 @@ +// Test for throwing bad_array_new_length on invalid array length +// { dg-options -std=c++11 } +// { dg-do run } + +#include + +void * f(int i) +{ + return new int[i]; +} + +int main() +{ + try + { + f(-1); + } + catch (std::bad_array_new_length) { return 0; } + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C b/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C new file mode 100644 index 0000000..ab36510 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C @@ -0,0 +1,21 @@ +// Test for throwing bad_array_new_length on invalid array length +// { dg-options -std=c++11 } +// { dg-do run } + +#include + +void * f(int i) +{ + return new int[i]{1,2,3,4}; +} + +int main() +{ + f(4); // OK + try + { + f(3); + } + catch (std::bad_array_new_length) { return 0; } + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist21.C b/gcc/testsuite/g++.dg/cpp0x/initlist21.C index 9412a08..16923f8 100644 --- a/gcc/testsuite/g++.dg/cpp0x/initlist21.C +++ b/gcc/testsuite/g++.dg/cpp0x/initlist21.C @@ -12,7 +12,6 @@ class X int f(int n) { const float * pData = new const float[1] { 1.5, 2.5 }; // { dg-error "too many initializers" } - pData = new const float[n] { 1.5, 2.5 }; // { dg-warning "array size" } return 0; } diff --git a/gcc/testsuite/g++.dg/init/new40.C b/gcc/testsuite/g++.dg/init/new40.C index 4b283a4..026712d 100644 --- a/gcc/testsuite/g++.dg/init/new40.C +++ b/gcc/testsuite/g++.dg/init/new40.C @@ -1,5 +1,7 @@ // Testcase for overflow handling in operator new[]. // Optimization of unnecessary overflow checks. +// In C++11 we throw bad_array_new_length instead. +// { dg-options -std=c++03 } // { dg-do run } #include diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 31019bf..f2b5e09 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,13 @@ +2013-05-08 Jason Merrill + + Add std::bad_array_new_length (N2932) + * libsupc++/new: Add std::bad_array_new_length. + * libsupc++/bad_array_new.cc: New. + * libsupc++/eh_aux_runtime.cc: Add __cxa_throw_bad_array_new_length. + * libsupc++/Makefile.in: Build them. + * config/abi/pre/gnu.ver: Add new symbols. + * config/abi/pre/gnu-versioned-namespace.ver: Add new symbols. + 2013-05-08 Andoni Morales Alastruey PR libstdc++/57212 diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver index 7880767..07feda0 100644 --- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver +++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver @@ -232,6 +232,9 @@ CXXABI_2.0 { _ZTSSt17bad_function_call; _ZTVSt17bad_function_call; + __cxa_throw_bad_array_new_length; + _Z*St20bad_array_new_length*; + # Default function. _ZSt11_Hash_bytesPKv*; diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 978641f..7256c6f 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -1556,6 +1556,10 @@ CXXABI_1.3.7 { __cxa_thread_atexit; } CXXABI_1.3.6; +CXXABI_1.3.8 { + __cxa_throw_bad_array_new_length; + _Z*St20bad_array_new_length*; +} CXXABI_1.3.7; # Symbols in the support library (libsupc++) supporting transactional memory. CXXABI_TM_1 { diff --git a/libstdc++-v3/libsupc++/Makefile.in b/libstdc++-v3/libsupc++/Makefile.in index eb13f1e..9f24fef 100644 --- a/libstdc++-v3/libsupc++/Makefile.in +++ b/libstdc++-v3/libsupc++/Makefile.in @@ -92,7 +92,8 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(bitsdir)" \ LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES) libsupc___la_LIBADD = am__objects_1 = array_type_info.lo atexit_arm.lo atexit_thread.lo \ - bad_alloc.lo bad_cast.lo bad_typeid.lo class_type_info.lo \ + bad_alloc.lo bad_array_new.lo bad_cast.lo bad_typeid.lo \ + class_type_info.lo \ del_op.lo del_opnt.lo del_opv.lo del_opvnt.lo dyncast.lo \ eh_alloc.lo eh_arm.lo eh_aux_runtime.lo eh_call.lo eh_catch.lo \ eh_exception.lo eh_globals.lo eh_personality.lo eh_ptr.lo \ @@ -366,6 +367,7 @@ sources = \ atexit_arm.cc \ atexit_thread.cc \ bad_alloc.cc \ + bad_array_new.cc \ bad_cast.cc \ bad_typeid.cc \ class_type_info.cc \ @@ -788,6 +790,16 @@ cp-demangle.o: cp-demangle.c $(C_COMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $< # Use special rules for the C++11 sources so that the proper flags are passed. +bad_array_new.lo: bad_array_new.cc + $(LTCXXCOMPILE) -std=gnu++11 -c $< +bad_array_new.o: bad_array_new.cc + $(CXXCOMPILE) -std=gnu++11 -c $< + +eh_aux_runtime.lo: eh_aux_runtime.cc + $(LTCXXCOMPILE) -std=gnu++11 -c $< +eh_aux_runtime.o: eh_aux_runtime.cc + $(CXXCOMPILE) -std=gnu++11 -c $< + eh_ptr.lo: eh_ptr.cc $(LTCXXCOMPILE) -std=gnu++11 -c $< eh_ptr.o: eh_ptr.cc diff --git a/libstdc++-v3/libsupc++/bad_array_new.cc b/libstdc++-v3/libsupc++/bad_array_new.cc new file mode 100644 index 0000000..5282f52 --- /dev/null +++ b/libstdc++-v3/libsupc++/bad_array_new.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2013 Free Software Foundation, Inc. +// +// This file is part of GCC. +// +// GCC is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3, or (at your option) +// any later version. + +// GCC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#include + +namespace std { + +bad_array_new_length::~bad_array_new_length() _GLIBCXX_USE_NOEXCEPT { } + +const char* +bad_array_new_length::what() const _GLIBCXX_USE_NOEXCEPT +{ + return "std::bad_array_new_length"; +} + +} // namespace std diff --git a/libstdc++-v3/libsupc++/cxxabi.h b/libstdc++-v3/libsupc++/cxxabi.h index f5301c0..83749ce 100644 --- a/libstdc++-v3/libsupc++/cxxabi.h +++ b/libstdc++-v3/libsupc++/cxxabi.h @@ -151,6 +151,9 @@ namespace __cxxabiv1 void __cxa_bad_typeid() __attribute__((__noreturn__)); + void + __cxa_throw_bad_array_new_length() __attribute__((__noreturn__)); + /** * @brief Demangling routine. diff --git a/libstdc++-v3/libsupc++/eh_aux_runtime.cc b/libstdc++-v3/libsupc++/eh_aux_runtime.cc index 7798014..1cc831b 100644 --- a/libstdc++-v3/libsupc++/eh_aux_runtime.cc +++ b/libstdc++-v3/libsupc++/eh_aux_runtime.cc @@ -24,6 +24,7 @@ #include "typeinfo" #include "exception" +#include "new" #include #include "unwind-cxx.h" #include @@ -36,3 +37,6 @@ extern "C" void __cxxabiv1::__cxa_bad_typeid () { _GLIBCXX_THROW_OR_ABORT(std::bad_typeid()); } +extern "C" void +__cxxabiv1::__cxa_throw_bad_array_new_length () +{ _GLIBCXX_THROW_OR_ABORT(std::bad_array_new_length()); } diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new index e3f0f77..3087502 100644 --- a/libstdc++-v3/libsupc++/new +++ b/libstdc++-v3/libsupc++/new @@ -64,6 +64,21 @@ namespace std virtual const char* what() const throw(); }; +#if __cplusplus >= 201103L + class bad_array_new_length : public bad_alloc + { + public: + bad_array_new_length() throw() { }; + + // This declaration is not useless: + // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118 + virtual ~bad_array_new_length() throw(); + + // See comment in eh_exception.cc. + virtual const char* what() const throw(); + }; +#endif + struct nothrow_t { }; extern const nothrow_t nothrow; -- 2.7.4