https://gcc.gnu.org/g:21bd348e140570a4caf4cc7fa8b5e906724583b6

commit r13-10368-g21bd348e140570a4caf4cc7fa8b5e906724583b6
Author: Richard Biener <[email protected]>
Date:   Mon Apr 13 13:18:00 2026 +0200

    tree-optimization/124868 - path isolation wrong-code
    
    The path isolation code mishandles the case where in the same block
    there's both a return of a local variable and a dereference of zero
    but from different edges.  In this case we re-use the produced block
    copy for both isolated paths, causing a trap on the path to the
    return of a non-local.
    
    The least intrusive change I came up with separates both causes
    and transforms, first isolating NULL dereferences and then
    isolating returns of non-NULL.  This will skip the latter transform
    on paths which will now not return anyway.
    
    To avoid duplicate diagnostics the handle_return_addr_local_phi_arg
    only diagnoses cases in blocks dominated by the original block, not in
    copies which still need SSA update and thus are falsely visited.
    
            PR tree-optimization/124868
            * gimple-ssa-isolate-paths.cc (handle_return_addr_local_phi_arg):
            Do not diagnose returns in blocks not dominated by the PHI.
            (find_implicit_erroneous_behavior): Do two sweeps over PHIs,
            first for NULL dereferences and then for local address returns.
    
            * gcc.dg/torture/pr124868.c: New testcase.
    
    (cherry picked from commit 935d483a80c7ab96d4e483e62a5c2cc138409ed3)

Diff:
---
 gcc/gimple-ssa-isolate-paths.cc         | 62 ++++++++++++++++++++++++---------
 gcc/testsuite/gcc.dg/torture/pr124868.c | 24 +++++++++++++
 2 files changed, 69 insertions(+), 17 deletions(-)

diff --git a/gcc/gimple-ssa-isolate-paths.cc b/gcc/gimple-ssa-isolate-paths.cc
index 7135435f0918..9486d3dc11f0 100644
--- a/gcc/gimple-ssa-isolate-paths.cc
+++ b/gcc/gimple-ssa-isolate-paths.cc
@@ -641,7 +641,8 @@ handle_return_addr_local_phi_arg (basic_block bb, 
basic_block duplicate,
       if (!return_stmt)
        continue;
 
-      if (gimple_return_retval (return_stmt) != lhs)
+      if (gimple_return_retval (return_stmt) != lhs
+         || !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
        continue;
 
       /* Add an entry for the return statement and the locations
@@ -715,24 +716,18 @@ find_implicit_erroneous_behavior (void)
         is then dereferenced within BB.  This is somewhat overly
         conservative, but probably catches most of the interesting
         cases.   */
+      basic_block duplicate = NULL;
       for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
        {
          gphi *phi = si.phi ();
          tree lhs = gimple_phi_result (phi);
 
-         /* Initial number of PHI arguments.  The result may change
-            from one iteration of the loop below to the next in
-            response to changes to the CFG but only the initial
-            value is stored below for use by diagnostics.  */
-         unsigned nargs = gimple_phi_num_args (phi);
-
          /* PHI produces a pointer result.  See if any of the PHI's
             arguments are NULL.
 
             When we remove an edge, we want to reprocess the current
             index since the argument at that index will have been
             removed, hence the ugly way we update I for each iteration.  */
-         basic_block duplicate = NULL;
          for (unsigned i = 0, next_i = 0;
               i < gimple_phi_num_args (phi); i = next_i)
            {
@@ -742,15 +737,6 @@ find_implicit_erroneous_behavior (void)
              /* Advance the argument index unless a path involving
                 the current argument has been isolated.  */
              next_i = i + 1;
-             bool isolated = false;
-             duplicate = handle_return_addr_local_phi_arg (bb, duplicate, lhs,
-                                                           arg, e, locmap,
-                                                           nargs, &isolated);
-             if (isolated)
-               {
-                 cfg_altered = true;
-                 next_i = i;
-               }
 
              if (!integer_zerop (arg))
                continue;
@@ -788,6 +774,48 @@ find_implicit_erroneous_behavior (void)
                }
            }
        }
+
+      /* Then look for a PHI which have addresses of locals that
+        are then returned.  */
+      duplicate = NULL;
+      for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
+       {
+         gphi *phi = si.phi ();
+         tree lhs = gimple_phi_result (phi);
+
+         /* Initial number of PHI arguments.  The result may change
+            from one iteration of the loop below to the next in
+            response to changes to the CFG but only the initial
+            value is stored below for use by diagnostics.  */
+         unsigned nargs = gimple_phi_num_args (phi);
+
+         /* PHI produces a pointer result.  See if any of the PHI's
+            arguments are NULL.
+
+            When we remove an edge, we want to reprocess the current
+            index since the argument at that index will have been
+            removed, hence the ugly way we update I for each iteration.  */
+         for (unsigned i = 0, next_i = 0;
+              i < gimple_phi_num_args (phi); i = next_i)
+           {
+             tree arg = gimple_phi_arg_def (phi, i);
+             edge e = gimple_phi_arg_edge (phi, i);
+
+             /* Advance the argument index unless a path involving
+                the current argument has been isolated.  */
+             next_i = i + 1;
+             bool isolated = false;
+             duplicate = handle_return_addr_local_phi_arg (bb, duplicate, lhs,
+                                                           arg, e, locmap,
+                                                           nargs, &isolated);
+             if (isolated)
+               {
+                 cfg_altered = true;
+                 next_i = i;
+               }
+           }
+       }
+
     }
 
   diag_returned_locals (false, locmap);
diff --git a/gcc/testsuite/gcc.dg/torture/pr124868.c 
b/gcc/testsuite/gcc.dg/torture/pr124868.c
new file mode 100644
index 000000000000..6f0f6612fc94
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr124868.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-additional-options "-fisolate-erroneous-paths-dereference" } */
+
+int a;
+static void __attribute__((noipa)) c(int b) {}
+static int * __attribute__((noipa))
+d()
+{
+  int g = 0, *h = &g;
+  if (a)
+    {
+      int **i = &h;
+      *i = 0;
+    }
+  c(*h);
+  return h; /* { dg-warning "address of local variable" } */
+}
+int
+main()
+{
+  d();
+  return 0;
+}

Reply via email to