aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2013-05-08 23:58:00 -0400
committerJason Merrill <jason@gcc.gnu.org>2013-05-08 23:58:00 -0400
commit7d5e76c8de1b6c4b2ae5576ab909dc9e580b216b (patch)
tree09467b7a6778576ce54cf16a985769ff3c2dacb8 /gcc
parentb0f36e5ee07dd1fa2d8345bcb1751aab3e95f980 (diff)
downloadgcc-7d5e76c8de1b6c4b2ae5576ab909dc9e580b216b.zip
gcc-7d5e76c8de1b6c4b2ae5576ab909dc9e580b216b.tar.gz
gcc-7d5e76c8de1b6c4b2ae5576ab909dc9e580b216b.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/call.c9
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/init.c46
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/bad_array_new1.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist21.C1
-rw-r--r--gcc/testsuite/g++.dg/init/new40.C2
8 files changed, 96 insertions, 10 deletions
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 <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.
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..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<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
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>