aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2012-11-07 10:45:57 +0100
committerFlorian Weimer <fw@gcc.gnu.org>2012-11-07 10:45:57 +0100
commit92d38f386bb23d45f15326edac74449064a6429d (patch)
tree712ee66f5a475c777251a49b6a28cdc8f3c3b420
parent7d57274b36a1aac0e2c38ab1073ce12b29f97ff4 (diff)
downloadgcc-92d38f386bb23d45f15326edac74449064a6429d.zip
gcc-92d38f386bb23d45f15326edac74449064a6429d.tar.gz
gcc-92d38f386bb23d45f15326edac74449064a6429d.tar.bz2
init.c (build_new_1): Do not check for arithmetic overflow if inner array size is 1.
* init.c (build_new_1): Do not check for arithmetic overflow if inner array size is 1. * g++.dg/init/new40.C: New. From-SVN: r193287
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/init.c20
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/init/new40.C112
4 files changed, 137 insertions, 4 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5e73e1b..c623b5e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,8 @@
+2012-11-07 Florian Weimer <fweimer@redhat.com>
+
+ * init.c (build_new_1): Do not check for arithmetic overflow if
+ inner array size is 1.
+
2012-11-05 Sriraman Tallam <tmsriram@google.com>
* class.c (add_method): Change assembler names of function versions.
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 013b01e..c842aac 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2185,6 +2185,8 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
bool outer_nelts_from_type = false;
double_int inner_nelts_count = double_int_one;
tree alloc_call, alloc_expr;
+ /* Size of the inner array elements. */
+ double_int inner_size;
/* The address returned by the call to "operator new". This node is
a VAR_DECL and is therefore reusable. */
tree alloc_node;
@@ -2346,8 +2348,6 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
double_int max_size
= double_int_one.llshift (TYPE_PRECISION (sizetype) - 1,
HOST_BITS_PER_DOUBLE_INT);
- /* Size of the inner array elements. */
- double_int inner_size;
/* Maximum number of outer elements which can be allocated. */
double_int max_outer_nelts;
tree max_outer_nelts_tree;
@@ -2451,7 +2451,13 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
if (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type))
size = size_binop (PLUS_EXPR, size, cookie_size);
else
- cookie_size = NULL_TREE;
+ {
+ cookie_size = NULL_TREE;
+ /* No size arithmetic necessary, so the size check is
+ not needed. */
+ if (outer_nelts_check != NULL && inner_size.is_one ())
+ outer_nelts_check = NULL_TREE;
+ }
/* Perform the overflow check. */
if (outer_nelts_check != NULL_TREE)
size = fold_build3 (COND_EXPR, sizetype, outer_nelts_check,
@@ -2487,7 +2493,13 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
/* Use a global operator new. */
/* See if a cookie might be required. */
if (!(array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type)))
- cookie_size = NULL_TREE;
+ {
+ cookie_size = NULL_TREE;
+ /* No size arithmetic necessary, so the size check is
+ not needed. */
+ if (outer_nelts_check != NULL && inner_size.is_one ())
+ outer_nelts_check = NULL_TREE;
+ }
alloc_call = build_operator_new_call (fnname, placement,
&size, &cookie_size,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8c5d5f3..5f10e41 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2012-11-07 Florian Weimer <fweimer@redhat.com>
+
+ * g++.dg/init/new40.C: New.
+
2012-11-07 Jakub Jelinek <jakub@redhat.com>
PR debug/54693
diff --git a/gcc/testsuite/g++.dg/init/new40.C b/gcc/testsuite/g++.dg/init/new40.C
new file mode 100644
index 0000000..4b283a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/new40.C
@@ -0,0 +1,112 @@
+// Testcase for overflow handling in operator new[].
+// Optimization of unnecessary overflow checks.
+// { dg-do run }
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdexcept>
+
+static size_t magic_allocation_size
+ = 1 + (size_t (1) << (sizeof (size_t) * 8 - 1));
+
+struct exc : std::bad_alloc {
+};
+
+static size_t expected_size;
+
+struct pod_with_new {
+ char ch;
+ void *operator new[] (size_t sz)
+ {
+ if (sz != expected_size)
+ abort ();
+ throw exc ();
+ }
+};
+
+struct with_new {
+ char ch;
+ with_new () { }
+ ~with_new () { }
+ void *operator new[] (size_t sz)
+ {
+ if (sz != size_t (-1))
+ abort ();
+ throw exc ();
+ }
+};
+
+struct non_pod {
+ char ch;
+ non_pod () { }
+ ~non_pod () { }
+};
+
+void *
+operator new (size_t sz) _GLIBCXX_THROW (std::bad_alloc)
+{
+ if (sz != expected_size)
+ abort ();
+ throw exc ();
+}
+
+int
+main ()
+{
+ if (sizeof (pod_with_new) == 1)
+ expected_size = magic_allocation_size;
+ else
+ expected_size = -1;
+
+ try {
+ new pod_with_new[magic_allocation_size];
+ abort ();
+ } catch (exc &) {
+ }
+
+ if (sizeof (with_new) == 1)
+ expected_size = magic_allocation_size;
+ else
+ expected_size = -1;
+
+ try {
+ new with_new[magic_allocation_size];
+ abort ();
+ } catch (exc &) {
+ }
+
+ expected_size = magic_allocation_size;
+ try {
+ new char[magic_allocation_size];
+ abort ();
+ } catch (exc &) {
+ }
+
+ expected_size = -1;
+
+ try {
+ new pod_with_new[magic_allocation_size][2];
+ abort ();
+ } catch (exc &) {
+ }
+
+ try {
+ new with_new[magic_allocation_size][2];
+ abort ();
+ } catch (exc &) {
+ }
+
+ try {
+ new char[magic_allocation_size][2];
+ abort ();
+ } catch (exc &) {
+ }
+
+ try {
+ new non_pod[magic_allocation_size];
+ abort ();
+ } catch (exc &) {
+ }
+
+ return 0;
+}