diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2024-07-17 19:38:12 +0100 |
---|---|---|
committer | Richard Sandiford <richard.sandiford@arm.com> | 2024-07-17 19:38:12 +0100 |
commit | 43a7ece873eba47a11c0b21b0068eee53740551a (patch) | |
tree | d1f41074993638652c7a013008a1dab971820764 | |
parent | 71b31690a7c52413496e91bcc5ee4c68af2f366f (diff) | |
download | gcc-43a7ece873eba47a11c0b21b0068eee53740551a.zip gcc-43a7ece873eba47a11c0b21b0068eee53740551a.tar.gz gcc-43a7ece873eba47a11c0b21b0068eee53740551a.tar.bz2 |
rtl-ssa: Fix move range canonicalisation [PR115929]
In this PR, canonicalize_move_range walked off the end of a list
and triggered a null dereference. There are multiple ways of fixing
that, but I think the approach taken in the patch should be
relatively efficient.
gcc/
PR rtl-optimization/115929
* rtl-ssa/movement.h (canonicalize_move_range): Check for null prev
and next insns and create an invalid move range for them.
gcc/testsuite/
PR rtl-optimization/115929
* gcc.dg/torture/pr115929-2.c: New test.
-rw-r--r-- | gcc/rtl-ssa/movement.h | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/pr115929-2.c | 22 |
2 files changed, 40 insertions, 2 deletions
diff --git a/gcc/rtl-ssa/movement.h b/gcc/rtl-ssa/movement.h index 17d31e0..ea1f788 100644 --- a/gcc/rtl-ssa/movement.h +++ b/gcc/rtl-ssa/movement.h @@ -76,9 +76,25 @@ inline bool canonicalize_move_range (insn_range_info &move_range, insn_info *insn) { while (move_range.first != insn && !can_insert_after (move_range.first)) - move_range.first = move_range.first->next_nondebug_insn (); + if (auto *next = move_range.first->next_nondebug_insn ()) + move_range.first = next; + else + { + // Invalidate the range. prev_nondebug_insn is always nonnull + // if next_nondebug_insn is null. + move_range.last = move_range.first->prev_nondebug_insn (); + return false; + } while (move_range.last != insn && !can_insert_after (move_range.last)) - move_range.last = move_range.last->prev_nondebug_insn (); + if (auto *prev = move_range.last->prev_nondebug_insn ()) + move_range.last = prev; + else + { + // Invalidate the range. next_nondebug_insn is always nonnull + // if prev_nondebug_insn is null. + move_range.first = move_range.last->next_nondebug_insn (); + return false; + } return bool (move_range); } diff --git a/gcc/testsuite/gcc.dg/torture/pr115929-2.c b/gcc/testsuite/gcc.dg/torture/pr115929-2.c new file mode 100644 index 0000000..c8473a7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr115929-2.c @@ -0,0 +1,22 @@ +/* { dg-additional-options "-fschedule-insns" } */ + +int a, b, c, d, e, f; +int main() { + if (e && f) + while (1) + while (a) + a = 0; + if (c) { + if (b) + goto g; + int h = a; + i: + b = ~((b ^ h) | 1 % b); + if (a) + g: + b = 0; + } + if (d) + goto i; + return 0; +} |