From: Mark Mitchell Date: Sun, 13 Apr 2003 17:54:03 +0000 (+0000) Subject: re PR c++/10300 (use of array-new (nothrow) in segfaults on NULL return) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f4f4610e036e239fb770127439d276439a621e3f;p=gcc.git re PR c++/10300 (use of array-new (nothrow) in segfaults on NULL return) PR c++/10300 * init.c (build_new_1): Reorganize. PR c++/10300 * g++.dg/init/new5.C: New test. From-SVN: r65550 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 40a2810f152..b520d2c1bb2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2003-04-12 Mark Mitchell + + PR c++/10300 + * init.c (build_new_1): Reorganize. + 2003-04-12 Zack Weinberg * class.c (initialize_array) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 3083412786e..d4beb0b751c 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2154,13 +2154,24 @@ build_new_1 (exp) tree exp; { tree placement, init; - tree type, true_type, size, rval, t; + tree true_type, size, rval, t; + /* The type of the new-expression. (This type is always a pointer + type.) */ + tree pointer_type; + /* The type pointed to by POINTER_TYPE. */ + tree type; + /* The type being allocated. For "new T[...]" this will be an + ARRAY_TYPE. */ tree full_type; + /* A pointer type pointing to to the FULL_TYPE. */ + tree full_pointer_type; tree outer_nelts = NULL_TREE; tree nelts = NULL_TREE; - tree alloc_call, alloc_expr, alloc_node; + tree alloc_call, alloc_expr; + /* The address returned by the call to "operator new". This node is + a VAR_DECL and is therefore reusable. */ + tree alloc_node; tree alloc_fn; - tree cookie_expr, init_expr; int has_array = 0; enum tree_code code; int nothrow, check_new; @@ -2175,6 +2186,14 @@ build_new_1 (exp) function. */ bool placement_allocation_fn_p; tree args = NULL_TREE; + /* True if the storage must be initialized, either by a constructor + or due to an explicit new-intiailizer. */ + bool is_initialized; + /* The address of the thing allocated, not including any cookie. In + particular, if an array cookie is in use, DATA_ADDR is the + address of the first array element. This node is a VAR_DECL, and + is therefore reusable. */ + tree data_addr; placement = TREE_OPERAND (exp, 0); type = TREE_OPERAND (exp, 1); @@ -2218,6 +2237,13 @@ build_new_1 (exp) if (abstract_virtuals_error (NULL_TREE, true_type)) return error_mark_node; + is_initialized = (TYPE_NEEDS_CONSTRUCTING (type) || init); + if (CP_TYPE_CONST_P (true_type) && !is_initialized) + { + error ("uninitialized const in `new' of `%#T'", true_type); + return error_mark_node; + } + size = size_in_bytes (true_type); if (has_array) size = size_binop (MULT_EXPR, size, convert (sizetype, nelts)); @@ -2321,44 +2347,49 @@ build_new_1 (exp) nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn)); check_new = (flag_check_new || nothrow) && ! use_java_new; - alloc_expr = alloc_call; - - if (cookie_size) - /* Adjust so we're pointing to the start of the object. */ - alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr), - alloc_expr, cookie_size); + /* In the simple case, we can stop now. */ + pointer_type = build_pointer_type (type); + if (!cookie_size && !is_initialized) + return build_nop (pointer_type, alloc_call); /* While we're working, use a pointer to the type we've actually - allocated. */ - alloc_expr = convert (build_pointer_type (full_type), alloc_expr); - - /* Now save the allocation expression so we only evaluate it once. */ - alloc_expr = get_target_expr (alloc_expr); + allocated. Store the result of the call in a variable so that we + can use it more than once. */ + full_pointer_type = build_pointer_type (full_type); + alloc_expr = get_target_expr (build_nop (full_pointer_type, alloc_call)); alloc_node = TREE_OPERAND (alloc_expr, 0); + rval = NULL_TREE; - /* Now initialize the cookie. */ if (cookie_size) { tree cookie; + tree cookie_expr; + + /* Adjust so we're pointing to the start of the object. */ + data_addr = get_target_expr (build (PLUS_EXPR, full_pointer_type, + alloc_node, cookie_size)); /* Store the number of bytes allocated so that we can know how many elements to destroy later. We use the last sizeof (size_t) bytes to store the number of elements. */ cookie = build (MINUS_EXPR, build_pointer_type (sizetype), - alloc_node, size_in_bytes (sizetype)); + data_addr, size_in_bytes (sizetype)); cookie = build_indirect_ref (cookie, NULL); - cookie_expr = build (MODIFY_EXPR, void_type_node, cookie, nelts); + cookie_expr = build (MODIFY_EXPR, sizetype, cookie, nelts); TREE_SIDE_EFFECTS (cookie_expr) = 1; + rval = build (COMPOUND_EXPR, void_type_node, data_addr, cookie_expr); + data_addr = TREE_OPERAND (data_addr, 0); } else - cookie_expr = NULL_TREE; + data_addr = alloc_node; /* Now initialize the allocated object. */ - init_expr = NULL_TREE; - if (TYPE_NEEDS_CONSTRUCTING (type) || init) + if (is_initialized) { - init_expr = build_indirect_ref (alloc_node, NULL); + tree init_expr; + + init_expr = build_indirect_ref (data_addr, NULL); if (init == void_zero_node) init = build_default_init (full_type, nelts); @@ -2415,22 +2446,13 @@ build_new_1 (exp) tree cleanup; int flags = (LOOKUP_NORMAL | (globally_qualified_p * LOOKUP_GLOBAL)); - tree delete_node; - - if (cookie_size) - /* Subtract the padding back out to get to the pointer returned - from operator new. */ - delete_node = fold (build (MINUS_EXPR, TREE_TYPE (alloc_node), - alloc_node, cookie_size)); - else - delete_node = alloc_node; /* The Standard is unclear here, but the right thing to do - is to use the same method for finding deallocation - functions that we use for finding allocation functions. */ + is to use the same method for finding deallocation + functions that we use for finding allocation functions. */ flags |= LOOKUP_SPECULATIVELY; - cleanup = build_op_delete_call (dcode, delete_node, size, flags, + cleanup = build_op_delete_call (dcode, alloc_node, size, flags, (placement_allocation_fn_p ? alloc_call : NULL_TREE)); @@ -2480,40 +2502,27 @@ build_new_1 (exp) end)); } } - } - else if (CP_TYPE_CONST_P (true_type)) - error ("uninitialized const in `new' of `%#T'", true_type); - - /* Now build up the return value in reverse order. */ - rval = alloc_node; + if (rval) + rval = build (COMPOUND_EXPR, TREE_TYPE (init_expr), rval, init_expr); + else + rval = init_expr; + } - if (init_expr) - rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval); - if (cookie_expr) - rval = build (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval); + rval = build (COMPOUND_EXPR, TREE_TYPE (alloc_node), rval, data_addr); - if (rval == alloc_node) - /* If we didn't modify anything, strip the TARGET_EXPR and return the - (adjusted) call. */ - rval = TREE_OPERAND (alloc_expr, 1); - else + if (check_new) { - if (check_new) - { - tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node, - integer_zero_node); - rval = build_conditional_expr (ifexp, rval, alloc_node); - } - - rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval); + tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node, integer_zero_node); + rval = build_conditional_expr (ifexp, rval, alloc_node); } - /* Now strip the outer ARRAY_TYPE, so we return a pointer to the first - element. */ - rval = convert (build_pointer_type (type), rval); + /* Perform the allocation before anything else, so that ALLOC_NODE + has been initialized before we start using it. */ + rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval); - return rval; + /* Convert to the final type. */ + return build_nop (pointer_type, rval); } static tree diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c7cae0a1818..b7366d617b1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2003-04-13 Mark Mitchell + + PR c++/10300 + * g++.dg/init/new5.C: New test. + 2003-04-12 Mark Mitchell PR c++/7910 diff --git a/gcc/testsuite/g++.dg/init/new5.C b/gcc/testsuite/g++.dg/init/new5.C new file mode 100644 index 00000000000..3a5981e075c --- /dev/null +++ b/gcc/testsuite/g++.dg/init/new5.C @@ -0,0 +1,18 @@ +// { dg-do run } + +#include + +void * operator new[](size_t, std::nothrow_t const &) throw() +{ return NULL; } + +struct X { + struct Inner { ~Inner() {} }; + + X() { + Inner * ic = new (std::nothrow) Inner[1]; // SegFault here + } +}; + +int main() { + X table; +}