Skip to content

Commit 5102777

Browse files
committed
Auto merge of #2973 - RalfJung:returnplace, r=RalfJung
test and fix return place alias restrictions
2 parents 9ed4669 + 0365101 commit 5102777

File tree

5 files changed

+124
-2
lines changed

5 files changed

+124
-2
lines changed

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,9 +514,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
514514
let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?;
515515
let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
516516
// Reborrow it. With protection! That is part of the point.
517-
// FIXME: do we truly want a 2phase borrow here?
518517
let new_perm = Some(NewPermission {
519-
initial_state: Permission::new_unique_2phase(/*freeze*/ false),
518+
initial_state: Permission::new_active(),
520519
zero_size: false,
521520
protector: Some(ProtectorKind::StrongProtector),
522521
});

src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ impl Permission {
138138
Self { inner: Reserved { ty_is_freeze } }
139139
}
140140

141+
/// Default initial permission for return place.
142+
pub fn new_active() -> Self {
143+
Self { inner: Active }
144+
}
145+
141146
/// Default initial permission of a reborrowed shared reference
142147
pub fn new_frozen() -> Self {
143148
Self { inner: Frozen }
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@revisions: stack tree
2+
//@[tree]compile-flags: -Zmiri-tree-borrows
3+
#![feature(raw_ref_op)]
4+
#![feature(core_intrinsics)]
5+
#![feature(custom_mir)]
6+
7+
use std::intrinsics::mir::*;
8+
use std::mem::MaybeUninit;
9+
10+
#[custom_mir(dialect = "runtime", phase = "optimized")]
11+
pub fn main() {
12+
mir! {
13+
{
14+
let x = 0;
15+
let ptr = &raw mut x;
16+
// We arrange for `myfun` to have a pointer that aliases
17+
// its return place. Even just reading from that pointer is UB.
18+
Call(*ptr, after_call, myfun(ptr))
19+
}
20+
21+
after_call = {
22+
Return()
23+
}
24+
}
25+
}
26+
27+
fn myfun(ptr: *mut i32) -> i32 {
28+
unsafe { ptr.cast::<MaybeUninit<i32>>().read() };
29+
//~[stack]^ ERROR: /not granting access/
30+
//~[tree]| ERROR: /read access .* forbidden/
31+
13
32+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
2+
--> $DIR/return_pointer_aliasing.rs:LL:CC
3+
|
4+
LL | unsafe { ptr.cast::<MaybeUninit<i32>>().read() };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected because it is an argument of call ID
6+
|
7+
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
8+
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
9+
help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
10+
--> $DIR/return_pointer_aliasing.rs:LL:CC
11+
|
12+
LL | / mir! {
13+
LL | | {
14+
LL | | let x = 0;
15+
LL | | let ptr = &raw mut x;
16+
... |
17+
LL | | }
18+
LL | | }
19+
| |_____^
20+
help: <TAG> is this argument
21+
--> $DIR/return_pointer_aliasing.rs:LL:CC
22+
|
23+
LL | / fn myfun(ptr: *mut i32) -> i32 {
24+
LL | | unsafe { ptr.cast::<MaybeUninit<i32>>().read() };
25+
LL | |
26+
LL | |
27+
LL | | 13
28+
LL | | }
29+
| |_^
30+
= note: BACKTRACE (of the first span):
31+
= note: inside `myfun` at $DIR/return_pointer_aliasing.rs:LL:CC
32+
note: inside `main`
33+
--> $DIR/return_pointer_aliasing.rs:LL:CC
34+
|
35+
LL | Call(*ptr, after_call, myfun(ptr))
36+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
37+
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
38+
39+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
40+
41+
error: aborting due to previous error
42+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error: Undefined Behavior: read access through <TAG> (root of the allocation) is forbidden
2+
--> $DIR/return_pointer_aliasing.rs:LL:CC
3+
|
4+
LL | unsafe { ptr.cast::<MaybeUninit<i32>>().read() };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ read access through <TAG> (root of the allocation) is forbidden
6+
|
7+
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
8+
= help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
9+
= help: this foreign read access would cause the protected tag <TAG> to transition from Active to Frozen
10+
= help: this transition would be a loss of write permissions, which is not allowed for protected tags
11+
help: the accessed tag <TAG> was created here
12+
--> $DIR/return_pointer_aliasing.rs:LL:CC
13+
|
14+
LL | / mir! {
15+
LL | | {
16+
LL | | let x = 0;
17+
LL | | let ptr = &raw mut x;
18+
... |
19+
LL | | }
20+
LL | | }
21+
| |_____^
22+
help: the protected tag <TAG> was created here, in the initial state Active
23+
--> $DIR/return_pointer_aliasing.rs:LL:CC
24+
|
25+
LL | / fn myfun(ptr: *mut i32) -> i32 {
26+
LL | | unsafe { ptr.cast::<MaybeUninit<i32>>().read() };
27+
LL | |
28+
LL | |
29+
LL | | 13
30+
LL | | }
31+
| |_^
32+
= note: BACKTRACE (of the first span):
33+
= note: inside `myfun` at $DIR/return_pointer_aliasing.rs:LL:CC
34+
note: inside `main`
35+
--> $DIR/return_pointer_aliasing.rs:LL:CC
36+
|
37+
LL | Call(*ptr, after_call, myfun(ptr))
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
39+
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
40+
41+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
42+
43+
error: aborting due to previous error
44+

0 commit comments

Comments
 (0)