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)
This commit is contained in:
Richard Biener 2024-05-10 14:19:49 +02:00
parent 81c627d47c
commit 1e9ae50d4d
2 changed files with 53 additions and 6 deletions

View file

@ -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;
}

View file

@ -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)