mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
b0f36e5ee0
commit
7d5e76c8de
|
|
@ -1,5 +1,11 @@
|
|||
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
|
||||
* decl.c (grokdeclarator): Warn about ref-qualifiers 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,
|
|||
*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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<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,
|
||||
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<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
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,13 @@
|
|||
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>
|
||||
|
||||
PR libstdc++/57212
|
||||
|
|
|
|||
|
|
@ -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*;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -151,6 +151,9 @@ namespace __cxxabiv1
|
|||
void
|
||||
__cxa_bad_typeid() __attribute__((__noreturn__));
|
||||
|
||||
void
|
||||
__cxa_throw_bad_array_new_length() __attribute__((__noreturn__));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Demangling routine.
|
||||
|
|
|
|||
|
|
@ -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_throw_bad_array_new_length ()
|
||||
{ _GLIBCXX_THROW_OR_ABORT(std::bad_array_new_length()); }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue