Commit 7d5e76c8 by Jason Merrill Committed by Jason Merrill

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
parent b0f36e5e
2013-05-08 Jason Merrill <jason@redhat.com> 2013-05-08 Jason Merrill <jason@redhat.com>
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 PR c++/57068
* decl.c (grokdeclarator): Warn about ref-qualifiers here. * decl.c (grokdeclarator): Warn about ref-qualifiers here.
* parser.c (cp_parser_ref_qualifier_seq_opt): Not here. * parser.c (cp_parser_ref_qualifier_seq_opt): Not here.
......
...@@ -3951,8 +3951,13 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args, ...@@ -3951,8 +3951,13 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
*fn = NULL_TREE; *fn = NULL_TREE;
/* Set to (size_t)-1 if the size check fails. */ /* Set to (size_t)-1 if the size check fails. */
if (size_check != NULL_TREE) 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); vec_safe_insert (*args, 0, *size);
*args = resolve_args (*args, complain); *args = resolve_args (*args, complain);
if (*args == NULL) if (*args == NULL)
......
...@@ -5357,6 +5357,7 @@ extern tree build_value_init (tree, tsubst_flags_t); ...@@ -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_value_init_noctor (tree, tsubst_flags_t);
extern tree build_offset_ref (tree, tree, bool, extern tree build_offset_ref (tree, tree, bool,
tsubst_flags_t); tsubst_flags_t);
extern tree throw_bad_array_new_length (void);
extern tree build_new (vec<tree, va_gc> **, tree, tree, extern tree build_new (vec<tree, va_gc> **, tree, tree,
vec<tree, va_gc> **, int, vec<tree, va_gc> **, int,
tsubst_flags_t); tsubst_flags_t);
......
...@@ -2170,6 +2170,21 @@ diagnose_uninitialized_cst_or_ref_member (tree type, bool using_new, bool compla ...@@ -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); 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 /* Generate code for a new-expression, including calling the "operator
new" function, initializing the object, and, if an exception occurs new" function, initializing the object, and, if an exception occurs
during construction, cleaning up. The arguments are as for 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, ...@@ -2472,9 +2487,12 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
outer_nelts_check = NULL_TREE; outer_nelts_check = NULL_TREE;
} }
/* Perform the overflow check. */ /* 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) if (outer_nelts_check != NULL_TREE)
size = fold_build3 (COND_EXPR, sizetype, outer_nelts_check, size = fold_build3 (COND_EXPR, sizetype, outer_nelts_check,
size, TYPE_MAX_VALUE (sizetype)); size, errval);
/* Create the argument list. */ /* Create the argument list. */
vec_safe_insert (*placement, 0, size); vec_safe_insert (*placement, 0, size);
/* Do name-lookup to find the appropriate operator. */ /* Do name-lookup to find the appropriate operator. */
...@@ -2699,12 +2717,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, ...@@ -2699,12 +2717,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
domain = compute_array_index_type (NULL_TREE, nelts, domain = compute_array_index_type (NULL_TREE, nelts,
complain); complain);
else else
{ /* We'll check the length at runtime. */
domain = NULL_TREE; domain = NULL_TREE;
if (CONSTRUCTOR_NELTS (vecinit) > 0)
warning (0, "non-constant array size in new, unable "
"to verify length of initializer-list");
}
arraytype = build_cplus_array_type (type, domain); arraytype = build_cplus_array_type (type, domain);
vecinit = digest_init (arraytype, vecinit, complain); vecinit = digest_init (arraytype, vecinit, complain);
} }
...@@ -3291,6 +3305,7 @@ build_vec_init (tree base, tree maxindex, tree init, ...@@ -3291,6 +3305,7 @@ build_vec_init (tree base, tree maxindex, tree init,
tree obase = base; tree obase = base;
bool xvalue = false; bool xvalue = false;
bool errors = false; bool errors = false;
tree length_check = NULL_TREE;
if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype)) if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
maxindex = array_type_nelts (atype); maxindex = array_type_nelts (atype);
...@@ -3309,6 +3324,14 @@ build_vec_init (tree base, tree maxindex, tree init, ...@@ -3309,6 +3324,14 @@ build_vec_init (tree base, tree maxindex, tree init,
&& from_array != 2) && from_array != 2)
init = TARGET_EXPR_INITIAL (init); 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 if (init
&& TREE_CODE (atype) == ARRAY_TYPE && TREE_CODE (atype) == ARRAY_TYPE
&& (from_array == 2 && (from_array == 2
...@@ -3441,6 +3464,15 @@ build_vec_init (tree base, tree maxindex, tree init, ...@@ -3441,6 +3464,15 @@ build_vec_init (tree base, tree maxindex, tree init,
vec<constructor_elt, va_gc> *new_vec; vec<constructor_elt, va_gc> *new_vec;
from_array = 0; 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) if (try_const)
vec_alloc (new_vec, CONSTRUCTOR_NELTS (init)); vec_alloc (new_vec, CONSTRUCTOR_NELTS (init));
else else
......
// 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 ();
}
// 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 ();
}
...@@ -12,7 +12,6 @@ class X ...@@ -12,7 +12,6 @@ class X
int f(int n) int f(int n)
{ {
const float * pData = new const float[1] { 1.5, 2.5 }; // { dg-error "too many initializers" } 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; return 0;
} }
// Testcase for overflow handling in operator new[]. // Testcase for overflow handling in operator new[].
// Optimization of unnecessary overflow checks. // Optimization of unnecessary overflow checks.
// In C++11 we throw bad_array_new_length instead.
// { dg-options -std=c++03 }
// { dg-do run } // { dg-do run }
#include <assert.h> #include <assert.h>
......
2013-05-08 Jason Merrill <jason@redhat.com>
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 <ylatuya@gmail.com> 2013-05-08 Andoni Morales Alastruey <ylatuya@gmail.com>
PR libstdc++/57212 PR libstdc++/57212
......
...@@ -232,6 +232,9 @@ CXXABI_2.0 { ...@@ -232,6 +232,9 @@ CXXABI_2.0 {
_ZTSSt17bad_function_call; _ZTSSt17bad_function_call;
_ZTVSt17bad_function_call; _ZTVSt17bad_function_call;
__cxa_throw_bad_array_new_length;
_Z*St20bad_array_new_length*;
# Default function. # Default function.
_ZSt11_Hash_bytesPKv*; _ZSt11_Hash_bytesPKv*;
......
...@@ -1556,6 +1556,10 @@ CXXABI_1.3.7 { ...@@ -1556,6 +1556,10 @@ CXXABI_1.3.7 {
__cxa_thread_atexit; __cxa_thread_atexit;
} CXXABI_1.3.6; } 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. # Symbols in the support library (libsupc++) supporting transactional memory.
CXXABI_TM_1 { CXXABI_TM_1 {
......
...@@ -92,7 +92,8 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(bitsdir)" \ ...@@ -92,7 +92,8 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(bitsdir)" \
LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES) LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES)
libsupc___la_LIBADD = libsupc___la_LIBADD =
am__objects_1 = array_type_info.lo atexit_arm.lo atexit_thread.lo \ 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 \ 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_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 \ eh_exception.lo eh_globals.lo eh_personality.lo eh_ptr.lo \
...@@ -366,6 +367,7 @@ sources = \ ...@@ -366,6 +367,7 @@ sources = \
atexit_arm.cc \ atexit_arm.cc \
atexit_thread.cc \ atexit_thread.cc \
bad_alloc.cc \ bad_alloc.cc \
bad_array_new.cc \
bad_cast.cc \ bad_cast.cc \
bad_typeid.cc \ bad_typeid.cc \
class_type_info.cc \ class_type_info.cc \
...@@ -788,6 +790,16 @@ cp-demangle.o: cp-demangle.c ...@@ -788,6 +790,16 @@ cp-demangle.o: cp-demangle.c
$(C_COMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $< $(C_COMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $<
# Use special rules for the C++11 sources so that the proper flags are passed. # 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 eh_ptr.lo: eh_ptr.cc
$(LTCXXCOMPILE) -std=gnu++11 -c $< $(LTCXXCOMPILE) -std=gnu++11 -c $<
eh_ptr.o: eh_ptr.cc eh_ptr.o: eh_ptr.cc
......
// 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
...@@ -151,6 +151,9 @@ namespace __cxxabiv1 ...@@ -151,6 +151,9 @@ namespace __cxxabiv1
void void
__cxa_bad_typeid() __attribute__((__noreturn__)); __cxa_bad_typeid() __attribute__((__noreturn__));
void
__cxa_throw_bad_array_new_length() __attribute__((__noreturn__));
/** /**
* @brief Demangling routine. * @brief Demangling routine.
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "typeinfo" #include "typeinfo"
#include "exception" #include "exception"
#include "new"
#include <cstdlib> #include <cstdlib>
#include "unwind-cxx.h" #include "unwind-cxx.h"
#include <bits/exception_defines.h> #include <bits/exception_defines.h>
...@@ -36,3 +37,6 @@ extern "C" void ...@@ -36,3 +37,6 @@ extern "C" void
__cxxabiv1::__cxa_bad_typeid () __cxxabiv1::__cxa_bad_typeid ()
{ _GLIBCXX_THROW_OR_ABORT(std::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()); }
...@@ -64,6 +64,21 @@ namespace std ...@@ -64,6 +64,21 @@ namespace std
virtual const char* what() const throw(); 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 { }; struct nothrow_t { };
extern const nothrow_t nothrow; extern const nothrow_t nothrow;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment