Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 618101 Details for
Bug 850911
g++: operator new[] overflow fix
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
gcc47-pr19351.patch
gcc47-pr19351.patch (text/plain), 15.57 KB, created by
Jakub Jelinek
on 2012-09-27 14:20:55 UTC
(
hide
)
Description:
gcc47-pr19351.patch
Filename:
MIME Type:
Creator:
Jakub Jelinek
Created:
2012-09-27 14:20:55 UTC
Size:
15.57 KB
patch
obsolete
>2012-09-27 Jakub Jelinek <jakub@redhat.com> > > * init.c (build_new_1): Don't test TREE_CONSTANT > of INTEGER_CST. > >2012-08-20 Florian Weimer <fweimer@redhat.com> > > PR c++/19351 > * call.c (build_operator_new_call): Add size_check argument and > evaluate it. > * cp-tree.h (build_operator_new_call): Adjust declaration. > * init.c (build_new_1): Compute array size check and apply it. > > * g++.dg/init/new38.C: New test. > * g++.dg/init/new39.C: New test. > >2012-06-25 Florian Weimer <fweimer@redhat.com> > > * g++.dg/init/new35.C: New. > * g++.dg/init/new36.C: New. > * g++.dg/init/new37.C: New. > >--- gcc/cp/call.c.jj 2012-09-13 18:45:00.352844422 +0200 >+++ gcc/cp/call.c 2012-09-27 14:13:11.367940506 +0200 >@@ -3906,15 +3906,19 @@ build_new_function_call (tree fn, VEC(tr > total number of bytes required by the allocation, and is updated if > that is changed here. *COOKIE_SIZE is non-NULL if a cookie should > be used. If this function determines that no cookie should be >- used, after all, *COOKIE_SIZE is set to NULL_TREE. If FN is >- non-NULL, it will be set, upon return, to the allocation function >- called. */ >+ used, after all, *COOKIE_SIZE is set to NULL_TREE. If SIZE_CHECK >+ is not NULL_TREE, it is evaluated before calculating the final >+ array size, and if it fails, the array size is replaced with >+ (size_t)-1 (usually triggering a std::bad_alloc exception). If FN >+ is non-NULL, it will be set, upon return, to the allocation >+ function called. */ > > tree > build_operator_new_call (tree fnname, VEC(tree,gc) **args, >- tree *size, tree *cookie_size, >+ tree *size, tree *cookie_size, tree size_check, > tree *fn) > { >+ tree original_size = *size; > tree fns; > struct z_candidate *candidates; > struct z_candidate *cand; >@@ -3922,6 +3926,10 @@ build_operator_new_call (tree fnname, VE > > if (fn) > *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)); > VEC_safe_insert (tree, gc, *args, 0, *size); > *args = resolve_args (*args, tf_warning_or_error); > if (*args == NULL) >@@ -3983,7 +3991,11 @@ build_operator_new_call (tree fnname, VE > if (use_cookie) > { > /* Update the total size. */ >- *size = size_binop (PLUS_EXPR, *size, *cookie_size); >+ *size = size_binop (PLUS_EXPR, original_size, *cookie_size); >+ /* Set to (size_t)-1 if the size check fails. */ >+ if (size_check != NULL_TREE) >+ *size = fold_build3 (COND_EXPR, sizetype, size_check, >+ *size, TYPE_MAX_VALUE (sizetype)); > /* Update the argument list to reflect the adjusted size. */ > VEC_replace (tree, *args, 0, *size); > } >--- gcc/cp/init.c.jj 2012-09-13 18:44:47.064913994 +0200 >+++ gcc/cp/init.c 2012-09-27 15:46:10.995316755 +0200 >@@ -2171,6 +2171,10 @@ build_new_1 (VEC(tree,gc) **placement, t > tree pointer_type; > tree non_const_pointer_type; > tree outer_nelts = NULL_TREE; >+ /* For arrays, a bounds checks on the NELTS parameter. */ >+ tree outer_nelts_check = NULL_TREE; >+ double_int inner_nelts_count = double_int_one; >+ tree inner_nelts = NULL_TREE; > tree alloc_call, alloc_expr; > /* The address returned by the call to "operator new". This node is > a VAR_DECL and is therefore reusable. */ >@@ -2216,10 +2220,42 @@ build_new_1 (VEC(tree,gc) **placement, t > for (elt_type = type; > TREE_CODE (elt_type) == ARRAY_TYPE; > elt_type = TREE_TYPE (elt_type)) >- nelts = cp_build_binary_op (input_location, >- MULT_EXPR, nelts, >- array_type_nelts_top (elt_type), >- complain); >+ { >+ tree this_inner_nelts = array_type_nelts_top (elt_type); >+ tree inner_nelts_cst = maybe_constant_value (this_inner_nelts); >+ if (TREE_CODE (inner_nelts_cst) == INTEGER_CST) >+ { >+ double_int result; >+ if (mul_double (TREE_INT_CST_LOW (inner_nelts_cst), >+ TREE_INT_CST_HIGH (inner_nelts_cst), >+ inner_nelts_count.low, inner_nelts_count.high, >+ &result.low, &result.high)) >+ { >+ if (complain & tf_error) >+ error ("integer overflow in array size"); >+ nelts = error_mark_node; >+ } >+ inner_nelts_count = result; >+ if (nelts != error_mark_node) >+ nelts = cp_build_binary_op (input_location, >+ MULT_EXPR, nelts, >+ inner_nelts_cst, >+ complain); >+ } >+ else if (inner_nelts == NULL_TREE) >+ inner_nelts = this_inner_nelts; >+ else >+ inner_nelts = cp_build_binary_op (input_location, >+ MULT_EXPR, inner_nelts, >+ this_inner_nelts, complain); >+ } >+ >+ if (nelts == error_mark_node) >+ return error_mark_node; >+ >+ if (inner_nelts) >+ nelts = cp_build_binary_op (input_location, MULT_EXPR, >+ nelts, inner_nelts, complain); > > if (TREE_CODE (elt_type) == VOID_TYPE) > { >@@ -2273,7 +2309,69 @@ build_new_1 (VEC(tree,gc) **placement, t > > size = size_in_bytes (elt_type); > if (array_p) >- size = size_binop (MULT_EXPR, size, convert (sizetype, nelts)); >+ { >+ /* Maximum available size in bytes. Half of the address space >+ minus the cookie size. */ >+ double_int max_size >+ = double_int_lshift (double_int_one, TYPE_PRECISION (sizetype) - 1, >+ HOST_BITS_PER_DOUBLE_INT, false); >+ /* 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; >+ >+ gcc_assert (TREE_CODE (size) == INTEGER_CST); >+ cookie_size = targetm.cxx.get_cookie_size (elt_type); >+ gcc_assert (TREE_CODE (cookie_size) == INTEGER_CST); >+ gcc_checking_assert (double_int_ucmp >+ (TREE_INT_CST (cookie_size), max_size) < 0); >+ /* Unconditionally substract the cookie size. This decreases the >+ maximum object size and is safe even if we choose not to use >+ a cookie after all. */ >+ max_size = double_int_sub (max_size, TREE_INT_CST (cookie_size)); >+ if (mul_double (TREE_INT_CST_LOW (size), TREE_INT_CST_HIGH (size), >+ inner_nelts_count.low, inner_nelts_count.high, >+ &inner_size.low, &inner_size.high) >+ || double_int_ucmp (inner_size, max_size) > 0) >+ { >+ if (complain & tf_error) >+ error ("size of array is too large"); >+ return error_mark_node; >+ } >+ max_outer_nelts = double_int_udiv (max_size, inner_size, TRUNC_DIV_EXPR); >+ /* Only keep the top-most seven bits, to simplify encoding the >+ constant in the instruction stream. */ >+ { >+ unsigned shift = HOST_BITS_PER_DOUBLE_INT - 7 >+ - (max_outer_nelts.high ? clz_hwi (max_outer_nelts.high) >+ : (HOST_BITS_PER_WIDE_INT + clz_hwi (max_outer_nelts.low))); >+ max_outer_nelts >+ = double_int_lshift (double_int_rshift >+ (max_outer_nelts, shift, >+ HOST_BITS_PER_DOUBLE_INT, false), >+ shift, HOST_BITS_PER_DOUBLE_INT, false); >+ } >+ max_outer_nelts_tree = double_int_to_tree (sizetype, max_outer_nelts); >+ >+ if (inner_nelts != NULL_TREE) >+ { >+ tree tem; >+ inner_nelts = save_expr (inner_nelts); >+ tem = fold_build3 (COND_EXPR, sizetype, >+ fold_build2 (NE_EXPR, boolean_type_node, >+ inner_nelts, size_zero_node), >+ inner_nelts, size_one_node); >+ max_outer_nelts_tree >+ = fold_build2 (TRUNC_DIV_EXPR, sizetype, >+ max_outer_nelts_tree, tem); >+ } >+ >+ size = size_binop (MULT_EXPR, size, convert (sizetype, nelts)); >+ outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node, >+ outer_nelts, >+ max_outer_nelts_tree); >+ } > > alloc_fn = NULL_TREE; > >@@ -2336,10 +2434,13 @@ build_new_1 (VEC(tree,gc) **placement, t > /* Use a class-specific operator new. */ > /* If a cookie is required, add some extra space. */ > if (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type)) >- { >- cookie_size = targetm.cxx.get_cookie_size (elt_type); >- size = size_binop (PLUS_EXPR, size, cookie_size); >- } >+ size = size_binop (PLUS_EXPR, size, cookie_size); >+ else >+ cookie_size = NULL_TREE; >+ /* Perform the overflow check. */ >+ if (outer_nelts_check != NULL_TREE) >+ size = fold_build3 (COND_EXPR, sizetype, outer_nelts_check, >+ size, TYPE_MAX_VALUE (sizetype)); > /* Create the argument list. */ > VEC_safe_insert (tree, gc, *placement, 0, size); > /* Do name-lookup to find the appropriate operator. */ >@@ -2370,13 +2471,12 @@ build_new_1 (VEC(tree,gc) **placement, t > { > /* Use a global operator new. */ > /* See if a cookie might be required. */ >- if (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type)) >- cookie_size = targetm.cxx.get_cookie_size (elt_type); >- else >+ if (!(array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type))) > cookie_size = NULL_TREE; > > alloc_call = build_operator_new_call (fnname, placement, > &size, &cookie_size, >+ outer_nelts_check, > &alloc_fn); > } > } >--- gcc/cp/cp-tree.h.jj 2012-09-13 18:45:01.000000000 +0200 >+++ gcc/cp/cp-tree.h 2012-09-27 14:14:11.665611825 +0200 >@@ -4863,7 +4863,7 @@ extern tree build_user_type_conversion > extern tree build_new_function_call (tree, VEC(tree,gc) **, bool, > tsubst_flags_t); > extern tree build_operator_new_call (tree, VEC(tree,gc) **, tree *, >- tree *, tree *); >+ tree *, tree, tree *); > extern tree build_new_method_call (tree, tree, VEC(tree,gc) **, > tree, int, tree *, > tsubst_flags_t); >--- gcc/testsuite/g++.dg/init/new35.C.jj 2012-09-27 15:49:36.125194709 +0200 >+++ gcc/testsuite/g++.dg/init/new35.C 2012-09-27 15:51:06.044702887 +0200 >@@ -0,0 +1,13 @@ >+// { dg-do compile } >+// { dg-options "" } >+ >+int >+main (int argc, char **argv) >+{ >+ typedef char A[argc]; >+ new A; >+ new A[0]; >+ new A[5]; >+ new (A[0]); >+ new (A[5]); >+} >--- gcc/testsuite/g++.dg/init/new36.C.jj 2012-09-27 15:49:36.125194709 +0200 >+++ gcc/testsuite/g++.dg/init/new36.C 2012-09-27 15:49:36.125194709 +0200 >@@ -0,0 +1,153 @@ >+// Testcase for invocation of constructors/destructors in operator new[]. >+// { dg-do run } >+ >+#include <stdlib.h> >+ >+struct E { >+ virtual ~E() { } >+}; >+ >+struct S { >+ S(); >+ ~S(); >+}; >+ >+static int count; >+static int max; >+static int throwAfter = -1; >+static S *pS; >+ >+S::S() >+{ >+ if (throwAfter >= 0 && count >= throwAfter) >+ throw E(); >+ if (pS) >+ { >+ ++pS; >+ if (this != pS) >+ abort(); >+ } >+ else >+ pS = this; >+ ++count; >+ max = count; >+} >+ >+S::~S() >+{ >+ if (count > 1) >+ { >+ if (this != pS) >+ abort(); >+ --pS; >+ } >+ else >+ pS = 0; >+ --count; >+} >+ >+void __attribute__((noinline)) doit(int n) >+{ >+ { >+ S *s = new S[n]; >+ if (count != n) >+ abort(); >+ if (pS != s + n - 1) >+ abort(); >+ delete [] s; >+ if (count != 0) >+ abort(); >+ } >+ throwAfter = 2; >+ max = 0; >+ try >+ { >+ new S[n]; >+ abort(); >+ } >+ catch (E) >+ { >+ if (max != 2) >+ abort(); >+ } >+ throwAfter = -1; >+} >+ >+int main() >+{ >+ { >+ S s; >+ if (count != 1) >+ abort(); >+ if (pS != &s) >+ abort(); >+ } >+ if (count != 0) >+ abort(); >+ { >+ S *s = new S; >+ if (count != 1) >+ abort(); >+ if (pS != s) >+ abort(); >+ delete s; >+ if (count != 0) >+ abort(); >+ } >+ { >+ S *s = new S[1]; >+ if (count != 1) >+ abort(); >+ if (pS != s) >+ abort(); >+ delete [] s; >+ if (count != 0) >+ abort(); >+ } >+ { >+ S *s = new S[5]; >+ if (count != 5) >+ abort(); >+ if (pS != s + 4) >+ abort(); >+ delete [] s; >+ if (count != 0) >+ abort(); >+ } >+ typedef S A[5]; >+ { >+ S *s = new A; >+ if (count != 5) >+ abort(); >+ if (pS != s + 4) >+ abort(); >+ delete [] s; >+ if (count != 0) >+ abort(); >+ } >+ throwAfter = 2; >+ max = 0; >+ try >+ { >+ new S[5]; >+ abort(); >+ } >+ catch (E) >+ { >+ if (max != 2) >+ abort(); >+ } >+ max = 0; >+ try >+ { >+ new A; >+ abort(); >+ } >+ catch (E) >+ { >+ if (max != 2) >+ abort(); >+ } >+ throwAfter = -1; >+ doit(5); >+} >--- gcc/testsuite/g++.dg/init/new37.C.jj 2012-09-27 15:49:36.126194704 +0200 >+++ gcc/testsuite/g++.dg/init/new37.C 2012-09-27 15:52:25.328269181 +0200 >@@ -0,0 +1,63 @@ >+// { dg-do compile } >+ >+void >+nonconst(int n) >+{ >+ new (long[n][n]); // { dg-error "variable length|array size|not a constant" } >+ new long[n][n]; // { dg-error "variable length|array size|not a constant|cannot appear in a constant-expression" } >+} >+ >+template <typename T> >+void * >+callnew(int n) >+{ >+ return new long[n][T::n]; >+} >+ >+template <typename T> >+void * >+callnew_fail_1(int n) >+{ >+ return new long[n][T::n]; // { dg-error "variable length|array size|usable in a constant" } >+} >+ >+template <typename T> >+void * >+callnew_fail_2() >+{ >+ return new long[T::n]; // { dg-error "size in array new" } >+} >+ >+template <typename T> >+void * >+callnew_fail_3() >+{ >+ return new T[2][T::n]; // { dg-error "size of array has non-integral type" } >+} >+ >+struct T1 { >+ static int n; >+}; >+ >+struct T2 { >+ static const double n = 2; // { dg-error "non-integral type" } >+}; >+ >+struct T3 { >+ static const int n = 2; >+}; >+ >+struct T4 { >+ enum { n = 3 }; >+}; >+ >+void >+test_callnew(int n) >+{ >+ new long[0.2]; // { dg-error "integral or enumeration type" } >+ callnew_fail_1<T1>(n); >+ callnew_fail_2<T2>(); >+ callnew_fail_3<T2>(); >+ callnew<T3>(n); >+ callnew<T4>(n); >+} >--- gcc/testsuite/g++.dg/init/new38.C.jj 2012-09-27 13:46:16.796733819 +0200 >+++ gcc/testsuite/g++.dg/init/new38.C 2012-09-27 13:46:16.805733771 +0200 >@@ -0,0 +1,54 @@ >+// { dg-do compile } >+ >+void >+large_array_char(int n) >+{ >+ new char[n] >+ [1ULL << (sizeof(void *) * 4)] >+ [1ULL << (sizeof(void *) * 4)]; // { dg-error "size of array" } >+} >+ >+template <typename T> >+void >+large_array_char_template(int n) >+{ >+ new char[n] >+ [1ULL << (sizeof(void *) * 4)] >+ [1ULL << (sizeof(void *) * 4)]; // { dg-error "size of array" } >+} >+ >+ >+template <typename T> >+void >+large_array_template1(int n) >+{ >+ new T[n] // { dg-error "size of array is too large" } >+ [(1ULL << (sizeof(void *) * 4)) / sizeof(T)] >+ [1ULL << (sizeof(void *) * 4)]; >+} >+ >+template <typename T> >+void >+large_array_template2(int n) >+{ >+ new T[n] // { dg-error "size of array is too large" } >+ [(1ULL << (sizeof(void *) * 4)) / sizeof(T)] >+ [1ULL << (sizeof(void *) * 4)]; >+} >+ >+template <typename T> >+void >+large_array_template3(int n) >+{ >+ new T[n] // { dg-error "size of array is too large" } >+ [(1ULL << (sizeof(void *) * 4)) / sizeof(T)] >+ [1ULL << (sizeof(void *) * 4)]; >+} >+ >+void >+call_large_array_template(int n) >+{ >+ large_array_template1<char>(n); >+ large_array_template2<int>(n); >+ large_array_template3<double>(n); >+} >--- gcc/testsuite/g++.dg/init/new39.C.jj 2012-09-27 13:46:16.805733771 +0200 >+++ gcc/testsuite/g++.dg/init/new39.C 2012-09-27 13:46:16.805733771 +0200 >@@ -0,0 +1,68 @@ >+// Testcase for overflow handling in operator new[]. >+// { dg-do run } >+ >+#include <stdlib.h> >+#include <stdexcept> >+ >+struct without_new { >+ char bar[256]; >+}; >+ >+struct with_new { >+ char bar[256]; >+ void *operator new[] (size_t sz) >+ { >+ if (sz != -1) >+ abort (); >+ throw std::bad_alloc(); >+ } >+}; >+ >+template <typename T> >+inline void >+test (size_t s) >+{ >+ try { >+ new T[s]; >+ abort (); >+ } catch (std::bad_alloc &) { >+ } >+} >+ >+template <typename T> >+void >+test_noopt (size_t s) __attribute__((noinline)); >+ >+template <typename T> >+void >+test_noopt (size_t s) >+{ >+ __asm__ (""); >+ test<T> (s); >+} >+ >+template <typename T> >+void >+all_tests () >+{ >+ test<T>(-1); >+ test<T>(size_t(-1) / sizeof (T) + 1); >+ test<T>(size_t(-1) / sizeof (T) + 2); >+ test_noopt<T>(-1); >+ test_noopt<T>(size_t(-1) / sizeof (T) + 1); >+ test_noopt<T>(size_t(-1) / sizeof (T) + 2); >+} >+ >+int >+main () >+{ >+ try { >+ ::operator new(size_t(-1)); >+ abort (); >+ } catch (std::bad_alloc &) { >+ } >+ all_tests<without_new> (); >+ all_tests<with_new> (); >+ return 0; >+} >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 850911
:
606350
|
608498
|
608499
| 618101 |
618142
|
618143