Commit f4f4610e by Mark Mitchell Committed by Mark Mitchell

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
parent 5de601cf
2003-04-12 Mark Mitchell <mark@codesourcery.com>
PR c++/10300
* init.c (build_new_1): Reorganize.
2003-04-12 Zack Weinberg <zack@codesourcery.com> 2003-04-12 Zack Weinberg <zack@codesourcery.com>
* class.c (initialize_array) * class.c (initialize_array)
......
...@@ -2154,13 +2154,24 @@ build_new_1 (exp) ...@@ -2154,13 +2154,24 @@ build_new_1 (exp)
tree exp; tree exp;
{ {
tree placement, init; 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; tree full_type;
/* A pointer type pointing to to the FULL_TYPE. */
tree full_pointer_type;
tree outer_nelts = NULL_TREE; tree outer_nelts = NULL_TREE;
tree 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 alloc_fn;
tree cookie_expr, init_expr;
int has_array = 0; int has_array = 0;
enum tree_code code; enum tree_code code;
int nothrow, check_new; int nothrow, check_new;
...@@ -2175,6 +2186,14 @@ build_new_1 (exp) ...@@ -2175,6 +2186,14 @@ build_new_1 (exp)
function. */ function. */
bool placement_allocation_fn_p; bool placement_allocation_fn_p;
tree args = NULL_TREE; 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); placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1); type = TREE_OPERAND (exp, 1);
...@@ -2218,6 +2237,13 @@ build_new_1 (exp) ...@@ -2218,6 +2237,13 @@ build_new_1 (exp)
if (abstract_virtuals_error (NULL_TREE, true_type)) if (abstract_virtuals_error (NULL_TREE, true_type))
return error_mark_node; 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); size = size_in_bytes (true_type);
if (has_array) if (has_array)
size = size_binop (MULT_EXPR, size, convert (sizetype, nelts)); size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
...@@ -2321,44 +2347,49 @@ build_new_1 (exp) ...@@ -2321,44 +2347,49 @@ build_new_1 (exp)
nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn)); nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
check_new = (flag_check_new || nothrow) && ! use_java_new; check_new = (flag_check_new || nothrow) && ! use_java_new;
alloc_expr = alloc_call; /* In the simple case, we can stop now. */
pointer_type = build_pointer_type (type);
if (cookie_size) if (!cookie_size && !is_initialized)
/* Adjust so we're pointing to the start of the object. */ return build_nop (pointer_type, alloc_call);
alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr),
alloc_expr, cookie_size);
/* While we're working, use a pointer to the type we've actually /* While we're working, use a pointer to the type we've actually
allocated. */ allocated. Store the result of the call in a variable so that we
alloc_expr = convert (build_pointer_type (full_type), alloc_expr); can use it more than once. */
full_pointer_type = build_pointer_type (full_type);
/* Now save the allocation expression so we only evaluate it once. */ alloc_expr = get_target_expr (build_nop (full_pointer_type, alloc_call));
alloc_expr = get_target_expr (alloc_expr);
alloc_node = TREE_OPERAND (alloc_expr, 0); alloc_node = TREE_OPERAND (alloc_expr, 0);
rval = NULL_TREE;
/* Now initialize the cookie. */
if (cookie_size) if (cookie_size)
{ {
tree cookie; 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 /* Store the number of bytes allocated so that we can know how
many elements to destroy later. We use the last sizeof many elements to destroy later. We use the last sizeof
(size_t) bytes to store the number of elements. */ (size_t) bytes to store the number of elements. */
cookie = build (MINUS_EXPR, build_pointer_type (sizetype), 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 = 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; 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 else
cookie_expr = NULL_TREE; data_addr = alloc_node;
/* Now initialize the allocated object. */ /* Now initialize the allocated object. */
init_expr = NULL_TREE; if (is_initialized)
if (TYPE_NEEDS_CONSTRUCTING (type) || init)
{ {
init_expr = build_indirect_ref (alloc_node, NULL); tree init_expr;
init_expr = build_indirect_ref (data_addr, NULL);
if (init == void_zero_node) if (init == void_zero_node)
init = build_default_init (full_type, nelts); init = build_default_init (full_type, nelts);
...@@ -2415,22 +2446,13 @@ build_new_1 (exp) ...@@ -2415,22 +2446,13 @@ build_new_1 (exp)
tree cleanup; tree cleanup;
int flags = (LOOKUP_NORMAL int flags = (LOOKUP_NORMAL
| (globally_qualified_p * LOOKUP_GLOBAL)); | (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 /* The Standard is unclear here, but the right thing to do
is to use the same method for finding deallocation is to use the same method for finding deallocation
functions that we use for finding allocation functions. */ functions that we use for finding allocation functions. */
flags |= LOOKUP_SPECULATIVELY; 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 (placement_allocation_fn_p
? alloc_call : NULL_TREE)); ? alloc_call : NULL_TREE));
...@@ -2480,40 +2502,27 @@ build_new_1 (exp) ...@@ -2480,40 +2502,27 @@ build_new_1 (exp)
end)); 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 (alloc_node), rval, data_addr);
rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval);
if (cookie_expr)
rval = build (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
if (rval == alloc_node) if (check_new)
/* 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) tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node, integer_zero_node);
{ rval = build_conditional_expr (ifexp, rval, alloc_node);
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);
} }
/* Now strip the outer ARRAY_TYPE, so we return a pointer to the first /* Perform the allocation before anything else, so that ALLOC_NODE
element. */ has been initialized before we start using it. */
rval = convert (build_pointer_type (type), rval); 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 static tree
......
2003-04-13 Mark Mitchell <mark@codesourcery.com>
PR c++/10300
* g++.dg/init/new5.C: New test.
2003-04-12 Mark Mitchell <mark@codesourcery.com> 2003-04-12 Mark Mitchell <mark@codesourcery.com>
PR c++/7910 PR c++/7910
......
// { dg-do run }
#include <new>
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment