public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-2772] c++: Prevent dangling pointers from becoming nullptr in constexpr [PR110619]
@ 2023-07-26  1:45 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2023-07-26  1:45 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b8266af71c19a0bd7db4d08c8d2ee3c33214508c

commit r14-2772-gb8266af71c19a0bd7db4d08c8d2ee3c33214508c
Author: Nathaniel Shead <nathanieloshead@gmail.com>
Date:   Sun Jul 23 01:14:37 2023 +1000

    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>

Diff:
---
 gcc/cp/cp-tree.h                              |  8 +++++++-
 gcc/cp/cp-gimplify.cc                         | 24 +++++++++++++++++++++---
 gcc/cp/semantics.cc                           |  4 +++-
 gcc/cp/typeck.cc                              |  9 +++++----
 gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C | 10 ++++++++++
 5 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3de0e154c12..e0c181d9aef 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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 &,
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index f5734197774..206e791fcfd 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -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:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8fb47fd179e..720521b7f1a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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);
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 859b133a18d..d5c0c85ed51 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C
new file mode 100644
index 00000000000..cca13302238
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-110619.C
@@ -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 );

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-07-26  1:45 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-26  1:45 [gcc r14-2772] c++: Prevent dangling pointers from becoming nullptr in constexpr [PR110619] Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).