Skip to content

Commit c217e07

Browse files
committed
Auto merge of rust-lang#2537 - saethlin:dont-back-up-too-far, r=RalfJung
Don't back up past the caller when looking for an FnEntry span Fixes rust-lang/miri#2536 This adds a fix for the logic as well as a regression test. In the new test `tests/fail/stacked_borrows/fnentry_invalidation2.rs`, before this PR, we display this diagnostic: ``` help: <3278> was later invalidated at offsets [0x0..0xc] by a Unique FnEntry retag --> tests/fail/stacked_borrows/fnentry_invalidation2.rs:13:5 | 13 | inner(&mut t); | ^^^^^^^^^^^^^ ``` Which is very misleading. It is not this call itself, but what happens within the call that invalidates the tag we want. With this PR, we get: ``` help: <2798> was later invalidated at offsets [0x0..0xc] by a Unique FnEntry retag inside this call --> tests/fail/stacked_borrows/fnentry_invalidation2.rs:20:13 | 20 | let _ = t.sli.as_mut_ptr(); | ^^^^^^^^^^^^^^^^^^ ``` Which is much better.
2 parents 6872a70 + 5f498ca commit c217e07

File tree

6 files changed

+77
-19
lines changed

6 files changed

+77
-19
lines changed

src/tools/miri/src/helpers.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod convert;
22

3+
use std::cmp;
34
use std::mem;
45
use std::num::NonZeroUsize;
56
use std::time::Duration;
@@ -908,24 +909,25 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> {
908909
/// This function is backed by a cache, and can be assumed to be very fast.
909910
pub fn get(&mut self) -> Span {
910911
let idx = self.current_frame_idx();
911-
Self::frame_span(self.machine, idx)
912+
self.stack().get(idx).map(Frame::current_span).unwrap_or(rustc_span::DUMMY_SP)
912913
}
913914

914-
/// Similar to `CurrentSpan::get`, but retrieves the parent frame of the first non-local frame.
915+
/// Returns the span of the *caller* of the current operation, again
916+
/// walking down the stack to find the closest frame in a local crate, if the caller of the
917+
/// current operation is not in a local crate.
915918
/// This is useful when we are processing something which occurs on function-entry and we want
916919
/// to point at the call to the function, not the function definition generally.
917-
pub fn get_parent(&mut self) -> Span {
918-
let idx = self.current_frame_idx();
919-
Self::frame_span(self.machine, idx.wrapping_sub(1))
920+
pub fn get_caller(&mut self) -> Span {
921+
// We need to go down at least to the caller (len - 2), or however
922+
// far we have to go to find a frame in a local crate.
923+
let local_frame_idx = self.current_frame_idx();
924+
let stack = self.stack();
925+
let idx = cmp::min(local_frame_idx, stack.len().saturating_sub(2));
926+
stack.get(idx).map(Frame::current_span).unwrap_or(rustc_span::DUMMY_SP)
920927
}
921928

922-
fn frame_span(machine: &MiriMachine<'_, '_>, idx: usize) -> Span {
923-
machine
924-
.threads
925-
.active_thread_stack()
926-
.get(idx)
927-
.map(Frame::current_span)
928-
.unwrap_or(rustc_span::DUMMY_SP)
929+
fn stack(&self) -> &[Frame<'mir, 'tcx, Provenance, machine::FrameData<'tcx>>] {
930+
self.machine.threads.active_thread_stack()
929931
}
930932

931933
fn current_frame_idx(&mut self) -> usize {

src/tools/miri/src/stacked_borrows/diagnostics.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,20 @@ enum InvalidationCause {
6666

6767
impl Invalidation {
6868
fn generate_diagnostic(&self) -> (String, SpanData) {
69-
(
69+
let message = if let InvalidationCause::Retag(_, RetagCause::FnEntry) = self.cause {
70+
// For a FnEntry retag, our Span points at the caller.
71+
// See `DiagnosticCx::log_invalidation`.
72+
format!(
73+
"{:?} was later invalidated at offsets {:?} by a {} inside this call",
74+
self.tag, self.range, self.cause
75+
)
76+
} else {
7077
format!(
7178
"{:?} was later invalidated at offsets {:?} by a {}",
7279
self.tag, self.range, self.cause
73-
),
74-
self.span.data(),
75-
)
80+
)
81+
};
82+
(message, self.span.data())
7683
}
7784
}
7885

@@ -275,7 +282,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir
275282
let (range, cause) = match &self.operation {
276283
Operation::Retag(RetagOp { cause, range, permission, .. }) => {
277284
if *cause == RetagCause::FnEntry {
278-
span = self.current_span.get_parent();
285+
span = self.current_span.get_caller();
279286
}
280287
(*range, InvalidationCause::Retag(permission.unwrap(), *cause))
281288
}

src/tools/miri/tests/fail/stacked_borrows/aliasing_mut3.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x4]
1414
|
1515
LL | safe_raw(xraw, xshr);
1616
| ^^^^
17-
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag
17+
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag inside this call
1818
--> $DIR/aliasing_mut3.rs:LL:CC
1919
|
2020
LL | safe_raw(xraw, xshr);

src/tools/miri/tests/fail/stacked_borrows/fnentry_invalidation.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
1414
|
1515
LL | let z = &mut x as *mut i32;
1616
| ^^^^^^
17-
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag
17+
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag inside this call
1818
--> $DIR/fnentry_invalidation.rs:LL:CC
1919
|
2020
LL | x.do_bad();
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Regression test for https://github.com/rust-lang/miri/issues/2536
2+
// This tests that we don't try to back too far up the stack when selecting a span to report.
3+
// We should display the as_mut_ptr() call as the location of the invalidation, not the call to
4+
// inner
5+
6+
struct Thing<'a> {
7+
sli: &'a mut [i32],
8+
}
9+
10+
fn main() {
11+
let mut t = Thing { sli: &mut [0, 1, 2] };
12+
let ptr = t.sli.as_ptr();
13+
inner(&mut t);
14+
unsafe {
15+
let _oof = *ptr; //~ ERROR: /read access .* tag does not exist in the borrow stack/
16+
}
17+
}
18+
19+
fn inner(t: &mut Thing) {
20+
let _ = t.sli.as_mut_ptr();
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: Undefined Behavior: attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
2+
--> $DIR/fnentry_invalidation2.rs:LL:CC
3+
|
4+
LL | let _oof = *ptr;
5+
| ^^^^
6+
| |
7+
| attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
8+
| this error occurs as part of an access at ALLOC[0x0..0x4]
9+
|
10+
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
11+
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
12+
help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0xc]
13+
--> $DIR/fnentry_invalidation2.rs:LL:CC
14+
|
15+
LL | let ptr = t.sli.as_ptr();
16+
| ^^^^^^^^^^^^^^
17+
help: <TAG> was later invalidated at offsets [0x0..0xc] by a Unique FnEntry retag inside this call
18+
--> $DIR/fnentry_invalidation2.rs:LL:CC
19+
|
20+
LL | let _ = t.sli.as_mut_ptr();
21+
| ^^^^^^^^^^^^^^^^^^
22+
= note: BACKTRACE:
23+
= note: inside `main` at $DIR/fnentry_invalidation2.rs:LL:CC
24+
25+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
26+
27+
error: aborting due to previous error
28+

0 commit comments

Comments
 (0)