https://gcc.gnu.org/g:34d15a4d630a0d54eddb99bdab086c506e10dac5
commit r15-362-g34d15a4d630a0d54eddb99bdab086c506e10dac5 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. 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)