aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2024-07-17 19:38:12 +0100
committerRichard Sandiford <richard.sandiford@arm.com>2024-07-17 19:38:12 +0100
commit43a7ece873eba47a11c0b21b0068eee53740551a (patch)
treed1f41074993638652c7a013008a1dab971820764
parent71b31690a7c52413496e91bcc5ee4c68af2f366f (diff)
downloadgcc-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.h20
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr115929-2.c22
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;
+}