From 2be4257abcce12927654580b5c156baf284ef398 Mon Sep 17 00:00:00 2001 From: dianne Date: Thu, 27 Aug 2026 01:55:12 -0700 Subject: [PATCH] add more fake reads to nested slice indexing --- compiler/rustc_mir_build/src/builder/expr/as_place.rs | 9 ++++++--- .../divergent-indexing-chain-soundness-failure.rs | 10 ++++++++++ .../divergent-indexing-chain-soundness-failure.stderr | 11 +++++++++++ .../divergent-indexing-chain-soundness-pass.rs | 11 +++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/ui/indexing/divergent-indexing-chain-soundness-failure.rs create mode 100644 tests/ui/indexing/divergent-indexing-chain-soundness-failure.stderr create mode 100644 tests/ui/indexing/divergent-indexing-chain-soundness-pass.rs diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index e92f74722626b..6a2d616de71c8 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -645,9 +645,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = self.bounds_check(block, &base_place, idx, expr_span, source_info); - if is_outermost_index { - self.read_fake_borrows(block, fake_borrow_temps, source_info) - } else { + // Keep all fake borrows we've collected so far alive. If we only emitted fake reads at the + // end, diverging within an index expression could make them unreachable. This would allow + // bounds checks to perform out-of-bounds accesses (#161852). + self.read_fake_borrows(block, fake_borrow_temps, source_info); + + if !is_outermost_index { self.add_fake_borrows_of_base( base_place.to_place(self), block, diff --git a/tests/ui/indexing/divergent-indexing-chain-soundness-failure.rs b/tests/ui/indexing/divergent-indexing-chain-soundness-failure.rs new file mode 100644 index 0000000000000..017184bd3f935 --- /dev/null +++ b/tests/ui/indexing/divergent-indexing-chain-soundness-failure.rs @@ -0,0 +1,10 @@ +//! Regression test for : we need to keep fake +//! borrows on indexed-into slice pointers alive for bounds-checks even if the end of the indexing +//! chain is unreachable. This prevents bounds-checks from performing out-of-bounds accesses. + +fn main() { + let mut x: &[&[&[u32]]] = &[&[&[0]]]; + let y: &[&[&[u32]]] = &[]; + x[0][{ x = y; 0 }][{ return; 0 }]; + //~^ ERROR: cannot assign `x` in indexing expression +} diff --git a/tests/ui/indexing/divergent-indexing-chain-soundness-failure.stderr b/tests/ui/indexing/divergent-indexing-chain-soundness-failure.stderr new file mode 100644 index 0000000000000..ad6adaab364eb --- /dev/null +++ b/tests/ui/indexing/divergent-indexing-chain-soundness-failure.stderr @@ -0,0 +1,11 @@ +error[E0510]: cannot assign `x` in indexing expression + --> $DIR/divergent-indexing-chain-soundness-failure.rs:8:12 + | +LL | x[0][{ x = y; 0 }][{ return; 0 }]; + | ---- ^^^^^ cannot assign + | | + | value is immutable in indexing expression + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0510`. diff --git a/tests/ui/indexing/divergent-indexing-chain-soundness-pass.rs b/tests/ui/indexing/divergent-indexing-chain-soundness-pass.rs new file mode 100644 index 0000000000000..e25b338129cb6 --- /dev/null +++ b/tests/ui/indexing/divergent-indexing-chain-soundness-pass.rs @@ -0,0 +1,11 @@ +//! Test documenting unusual behavior related to : +//! currently, fake reads for fake borrows on indexed-into slice pointers are emitted after bounds- +//! checks, to keep them alive for those. This does not keep fake borrows alive at points from which +//! all further bounds-checks are unreachable. +//@ check-pass + +fn main() { + let mut x: &[&[&[u32]]] = &[&[&[0]]]; + let y: &[&[&[u32]]] = &[]; + x[0][{ x = y; return; 0 }]; +}