https://gcc.gnu.org/g:1e9ae50d4d160f6d557fc4cbbe95c4a36897c09f

commit r14-10214-g1e9ae50d4d160f6d557fc4cbbe95c4a36897c09f
Author: Richard Biener <rguent...@suse.de>
Date:   Fri May 10 14:19:49 2024 +0200

    tree-optimization/114998 - use-after-free with loop distribution
    
    When loop distribution releases a PHI node of the original IL it
    can end up clobbering memory that's re-used when it upon releasing
    its RDG resets all stmt UIDs back to -1, even those that got released.
    
    The fix is to avoid resetting UIDs based on stmts in the RDG but
    instead reset only those still present in the loop.
    
            PR tree-optimization/114998
            * tree-loop-distribution.cc (free_rdg): Take loop argument.
            Reset UIDs of stmts still in the IL rather than all stmts
            referenced from the RDG.
            (loop_distribution::build_rdg): Pass loop to free_rdg.
            (loop_distribution::distribute_loop): Likewise.
            (loop_distribution::transform_reduction_loop): Likewise.
    
            * gcc.dg/torture/pr114998.c: New testcase.
    
    (cherry picked from commit 34d15a4d630a0d54eddb99bdab086c506e10dac5)

Diff:
---
 gcc/testsuite/gcc.dg/torture/pr114998.c | 35 +++++++++++++++++++++++++++++++++
 gcc/tree-loop-distribution.cc           | 24 ++++++++++++++++------
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/torture/pr114998.c 
b/gcc/testsuite/gcc.dg/torture/pr114998.c
new file mode 100644
index 000000000000..81fc1e077cb9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr114998.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fno-tree-dce -ftree-loop-distribution" } */
+
+short a, d;
+int b, c, f, g, h, i, j[2], o;
+__attribute__((const)) int s(char r);
+int main() {
+  int l, m, k, n;
+  if (b) {
+    char p;
+    for (; p >= 0; p--) {
+      int e[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
+                 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1,
+                 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0};
+      if (j[p]) {
+        int q[1];
+        i = o;
+        o = q[h];
+        if (g)
+          n = d;
+        m = 4;
+        for (; m; m--) {
+          if (l)
+            k |= c;
+          if (a)
+            break;
+        }
+      }
+      s(n);
+      f |= b;
+    }
+  }
+  return 0;
+}
diff --git a/gcc/tree-loop-distribution.cc b/gcc/tree-loop-distribution.cc
index 95203fefa188..45932bae5e7f 100644
--- a/gcc/tree-loop-distribution.cc
+++ b/gcc/tree-loop-distribution.cc
@@ -778,7 +778,7 @@ loop_distribution::stmts_from_loop (class loop *loop, 
vec<gimple *> *stmts)
 /* Free the reduced dependence graph RDG.  */
 
 static void
-free_rdg (struct graph *rdg)
+free_rdg (struct graph *rdg, loop_p loop)
 {
   int i;
 
@@ -792,13 +792,25 @@ free_rdg (struct graph *rdg)
 
       if (v->data)
        {
-         gimple_set_uid (RDGV_STMT (v), -1);
          (RDGV_DATAREFS (v)).release ();
          free (v->data);
        }
     }
 
   free_graph (rdg);
+
+  /* Reset UIDs of stmts still in the loop.  */
+  basic_block *bbs = get_loop_body (loop);
+  for (unsigned i = 0; i < loop->num_nodes; ++i)
+    {
+      basic_block bb = bbs[i];
+      gimple_stmt_iterator gsi;
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       gimple_set_uid (gsi_stmt (gsi), -1);
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       gimple_set_uid (gsi_stmt (gsi), -1);
+    }
+  free (bbs);
 }
 
 struct graph *
@@ -812,7 +824,7 @@ loop_distribution::build_rdg (class loop *loop, 
control_dependences *cd)
   rdg = new_graph (stmts.length ());
   if (!create_rdg_vertices (rdg, stmts, loop))
     {
-      free_rdg (rdg);
+      free_rdg (rdg, loop);
       return NULL;
     }
   stmts.release ();
@@ -3062,7 +3074,7 @@ loop_distribution::distribute_loop (class loop *loop,
                 "Loop %d not distributed: too many memory references.\n",
                 loop->num);
 
-      free_rdg (rdg);
+      free_rdg (rdg, loop);
       loop_nest.release ();
       free_data_refs (datarefs_vec);
       delete ddrs_table;
@@ -3259,7 +3271,7 @@ loop_distribution::distribute_loop (class loop *loop,
   FOR_EACH_VEC_ELT (partitions, i, partition)
     partition_free (partition);
 
-  free_rdg (rdg);
+  free_rdg (rdg, loop);
   return nbp - *nb_calls;
 }
 
@@ -3665,7 +3677,7 @@ loop_distribution::transform_reduction_loop (loop_p loop)
   auto_bitmap partition_stmts;
   bitmap_set_range (partition_stmts, 0, rdg->n_vertices);
   find_single_drs (loop, rdg, partition_stmts, &store_dr, &load_dr);
-  free_rdg (rdg);
+  free_rdg (rdg, loop);
 
   /* Bail out if there is no single load.  */
   if (load_dr == NULL)

Reply via email to