From 35dd1f6bfdea1358bacc85b30cd5d99bcae2d5e4 Mon Sep 17 00:00:00 2001 From: fw Date: Wed, 7 Nov 2012 09:45:57 +0000 Subject: [PATCH] * init.c (build_new_1): Do not check for arithmetic overflow if inner array size is 1. * g++.dg/init/new40.C: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@193287 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 5 ++ gcc/cp/init.c | 20 +++++-- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/g++.dg/init/new40.C | 112 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/init/new40.C 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 + + * init.c (build_new_1): Do not check for arithmetic overflow if + inner array size is 1. + 2012-11-05 Sriraman Tallam * 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 + + * g++.dg/init/new40.C: New. + 2012-11-07 Jakub Jelinek 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 +#include +#include + +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; +} -- 2.7.4