Hi Jason! On 2013-05-03T16:24:43-0400, Jason Merrill <ja...@redhat.com> wrote: > Last year Florian fixed the compiler to detect overflow in array new > size calculations and pass (size_t)-1 in that case. But C++11 specifies > that in case of overflow the program throws std::bad_array_new_length > (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#624), so > I've adjusted the checking code accordingly. > > This patch also adds the type to libsupc++, and several exports to > libstdc++. > > Tested x86_64-pc-linux-gnu, applying to trunk.
Subversion r198731 (Git commit 7d5e76c8de1b6c4b2ae5576ab909dc9e580b216b). > 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_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. Here: > --- a/gcc/cp/init.c > +++ b/gcc/cp/init.c > +/* 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_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); > +} "Pretend it returns sizetype", doesn't work with nvptx, which complains that the front end-synthesized prototype with the fake 'sizetype' return type: .extern .func (.param .u64 %value_out) __cxa_throw_bad_array_new_length; ... doesn't match the library code with 'void' return type: > --- a/libstdc++-v3/libsupc++/cxxabi.h > +++ b/libstdc++-v3/libsupc++/cxxabi.h > + void > + __cxa_bad_array_new_length() __attribute__((__noreturn__)); > --- a/libstdc++-v3/libsupc++/eh_aux_runtime.cc > +++ b/libstdc++-v3/libsupc++/eh_aux_runtime.cc > +extern "C" void > +__cxxabiv1::__cxa_bad_array_new_length () > +{ _GLIBCXX_THROW_OR_ABORT(std::bad_array_new_length()); } .visible .func __cxa_throw_bad_array_new_length { [...] } ..., and thus results in execution test FAILs: error : Prototype doesn't match for '__cxa_throw_bad_array_new_length' in 'input file 5 at offset 14095', first defined in 'input file 5 at offset 14095' nvptx-run: cuLinkAddData failed: device kernel image is invalid (CUDA_ERROR_INVALID_SOURCE, 300) How can we improve on "Pretend it returns sizetype"? Is there a standard way to "bend" the types in the front end? Grüße Thomas > 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<tree, va_gc> > **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, va_gc> **, > tree, tree, > vec<tree, va_gc> **, int, > tsubst_flags_t); > diff --git a/gcc/cp/init.c b/gcc/cp/init.c > index 3587b08..73186eb 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_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<tree, va_gc> **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<tree, va_gc> **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, > + ssize_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<constructor_elt, va_gc> *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 <new> > + > +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 <new> > + > +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 <assert.h> > diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver > b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver > index 7880767..122ebb8 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_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..84b0b91 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_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 > +// <http://www.gnu.org/licenses/>. > + > +#include <new> > + > +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..a062a46 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_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..dcfef6b 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 <cstdlib> > #include "unwind-cxx.h" > #include <bits/exception_defines.h> > @@ -36,3 +37,6 @@ extern "C" void > __cxxabiv1::__cxa_bad_typeid () > { _GLIBCXX_THROW_OR_ABORT(std::bad_typeid()); } > > +extern "C" void > +__cxxabiv1::__cxa_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;