c++: Prevent dangling pointers from becoming nullptr in constexpr [PR110619]
Currently, when typeck discovers that a return statement will refer to a local variable it rewrites to return a null pointer. This causes the error messages for using the return value in a constant expression to be unhelpful, especially for reference return values, and is also a visible change to otherwise valid code (as in the linked PR). The transformation is nonetheless important, however, both as a safety guard against attackers being able to gain a handle to other data on the stack, and to prevent duplicate warnings from later null-dereference warning passes. As such, this patch just delays the transformation until cp_genericize, after constexpr function definitions have been generated. PR c++/110619 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_genericize_r): Transform RETURN_EXPRs to not return dangling pointers. * cp-tree.h (RETURN_EXPR_LOCAL_ADDR_P): New flag. (check_return_expr): Add a new parameter. * semantics.cc (finish_return_stmt): Set flag on RETURN_EXPR when referring to dangling pointer. * typeck.cc (check_return_expr): Disable transformation of dangling pointers, instead pass this information to caller. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/constexpr-110619.C: New test. Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
This commit is contained in:
parent
5ebe5bcf8b
commit
b8266af71c
5 changed files with 46 additions and 9 deletions
|
@ -1336,9 +1336,27 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
|
|||
break;
|
||||
|
||||
case RETURN_EXPR:
|
||||
if (TREE_OPERAND (stmt, 0) && is_invisiref_parm (TREE_OPERAND (stmt, 0)))
|
||||
/* Don't dereference an invisiref RESULT_DECL inside a RETURN_EXPR. */
|
||||
*walk_subtrees = 0;
|
||||
if (TREE_OPERAND (stmt, 0))
|
||||
{
|
||||
if (is_invisiref_parm (TREE_OPERAND (stmt, 0)))
|
||||
/* Don't dereference an invisiref RESULT_DECL inside a
|
||||
RETURN_EXPR. */
|
||||
*walk_subtrees = 0;
|
||||
if (RETURN_EXPR_LOCAL_ADDR_P (stmt))
|
||||
{
|
||||
/* Don't return the address of a local variable. */
|
||||
tree *p = &TREE_OPERAND (stmt, 0);
|
||||
while (TREE_CODE (*p) == COMPOUND_EXPR)
|
||||
p = &TREE_OPERAND (*p, 0);
|
||||
if (TREE_CODE (*p) == INIT_EXPR)
|
||||
{
|
||||
tree op = TREE_OPERAND (*p, 1);
|
||||
tree new_op = build2 (COMPOUND_EXPR, TREE_TYPE (op), op,
|
||||
build_zero_cst (TREE_TYPE (op)));
|
||||
TREE_OPERAND (*p, 1) = new_op;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OMP_CLAUSE:
|
||||
|
|
|
@ -447,6 +447,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
|
|||
INIT_EXPR_NRV_P (in INIT_EXPR)
|
||||
ATOMIC_CONSTR_MAP_INSTANTIATED_P (in ATOMIC_CONSTR)
|
||||
contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
|
||||
RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR)
|
||||
1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
|
||||
TI_PENDING_TEMPLATE_FLAG.
|
||||
TEMPLATE_PARMS_FOR_INLINE.
|
||||
|
@ -4071,6 +4072,11 @@ struct GTY(()) lang_decl {
|
|||
(LANG_DECL_FN_CHECK (FUNCTION_DECL_CHECK (NODE)) \
|
||||
->u.saved_auto_return_type)
|
||||
|
||||
/* In a RETURN_EXPR, whether the expression refers to the address
|
||||
of a local variable. */
|
||||
#define RETURN_EXPR_LOCAL_ADDR_P(NODE) \
|
||||
TREE_LANG_FLAG_0 (RETURN_EXPR_CHECK (NODE))
|
||||
|
||||
/* True if NODE is an implicit INDIRECT_REF from convert_from_reference. */
|
||||
#define REFERENCE_REF_P(NODE) \
|
||||
(INDIRECT_REF_P (NODE) \
|
||||
|
@ -8139,7 +8145,7 @@ extern tree composite_pointer_type (const op_location_t &,
|
|||
tsubst_flags_t);
|
||||
extern tree merge_types (tree, tree);
|
||||
extern tree strip_array_domain (tree);
|
||||
extern tree check_return_expr (tree, bool *);
|
||||
extern tree check_return_expr (tree, bool *, bool *);
|
||||
extern tree spaceship_type (tree, tsubst_flags_t = tf_warning_or_error);
|
||||
extern tree genericize_spaceship (location_t, tree, tree, tree);
|
||||
extern tree cp_build_binary_op (const op_location_t &,
|
||||
|
|
|
@ -1240,8 +1240,9 @@ finish_return_stmt (tree expr)
|
|||
{
|
||||
tree r;
|
||||
bool no_warning;
|
||||
bool dangling;
|
||||
|
||||
expr = check_return_expr (expr, &no_warning);
|
||||
expr = check_return_expr (expr, &no_warning, &dangling);
|
||||
|
||||
if (error_operand_p (expr)
|
||||
|| (flag_openmp && !check_omp_return ()))
|
||||
|
@ -1259,6 +1260,7 @@ finish_return_stmt (tree expr)
|
|||
}
|
||||
|
||||
r = build_stmt (input_location, RETURN_EXPR, expr);
|
||||
RETURN_EXPR_LOCAL_ADDR_P (r) = dangling;
|
||||
if (no_warning)
|
||||
suppress_warning (r, OPT_Wreturn_type);
|
||||
r = maybe_cleanup_point_expr_void (r);
|
||||
|
|
|
@ -10920,10 +10920,11 @@ maybe_warn_pessimizing_move (tree expr, tree type, bool return_p)
|
|||
change RETVAL into the function return type, and to assign it to
|
||||
the DECL_RESULT for the function. Set *NO_WARNING to true if
|
||||
code reaches end of non-void function warning shouldn't be issued
|
||||
on this RETURN_EXPR. */
|
||||
on this RETURN_EXPR. Set *DANGLING to true if code returns the
|
||||
address of a local variable. */
|
||||
|
||||
tree
|
||||
check_return_expr (tree retval, bool *no_warning)
|
||||
check_return_expr (tree retval, bool *no_warning, bool *dangling)
|
||||
{
|
||||
tree result;
|
||||
/* The type actually returned by the function. */
|
||||
|
@ -10935,6 +10936,7 @@ check_return_expr (tree retval, bool *no_warning)
|
|||
location_t loc = cp_expr_loc_or_input_loc (retval);
|
||||
|
||||
*no_warning = false;
|
||||
*dangling = false;
|
||||
|
||||
/* A `volatile' function is one that isn't supposed to return, ever.
|
||||
(This is a G++ extension, used to get better code for functions
|
||||
|
@ -11273,8 +11275,7 @@ check_return_expr (tree retval, bool *no_warning)
|
|||
else if (!processing_template_decl
|
||||
&& maybe_warn_about_returning_address_of_local (retval, loc)
|
||||
&& INDIRECT_TYPE_P (valtype))
|
||||
retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
|
||||
build_zero_cst (TREE_TYPE (retval)));
|
||||
*dangling = true;
|
||||
}
|
||||
|
||||
/* A naive attempt to reduce the number of -Wdangling-reference false
|
||||
|
|
10
gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C
Normal file
10
gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C
Normal file
|
@ -0,0 +1,10 @@
|
|||
// { dg-do compile { target c++14 } }
|
||||
// { dg-options "-Wno-return-local-addr" }
|
||||
// PR c++/110619
|
||||
|
||||
constexpr auto f() {
|
||||
int i = 0;
|
||||
return &i;
|
||||
};
|
||||
|
||||
static_assert( f() != nullptr );
|
Loading…
Add table
Reference in a new issue