Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions compiler/rustc_mir_build/src/builder/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment on lines -648 to +651

@dianne dianne Aug 27, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes the total number of fake reads quadratic in how much nested slice indexing we do, but hopefully that'd only matter in stress tests? Surprisingly, no MIR building tests needed blessing, so I don't have an example to point to.

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs 3 or more nested array/slice indexes, so it's not that surprising that no tests are affected. It definitely doesn't seem likely that there's any real code that's going to have large enough numbers of nested indexes for this to have a significant impact.


if !is_outermost_index {
self.add_fake_borrows_of_base(
base_place.to_place(self),
block,
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/indexing/divergent-indexing-chain-soundness-failure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/161852>: 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
}
Original file line number Diff line number Diff line change
@@ -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`.
11 changes: 11 additions & 0 deletions tests/ui/indexing/divergent-indexing-chain-soundness-pass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Test documenting unusual behavior related to <https://github.com/rust-lang/rust/issues/161852>:
//! 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 }];
}
Loading