Skip to content

Commit 2de6e7f

Browse files
committed
Implement fix for reservedim_spurious_write: ignore IM on protected
1 parent 22364f8 commit 2de6e7f

File tree

6 files changed

+59
-7
lines changed

6 files changed

+59
-7
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,14 @@ impl<'tcx> NewPermission {
141141
) -> Option<Self> {
142142
let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env());
143143
let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env());
144+
let is_protected = kind == RetagKind::FnEntry;
145+
// As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`,
146+
// interior mutability and protectors interact poorly.
147+
// To eliminate the case of Protected Reserved IM we override interior mutability
148+
// in the case of a protected reference.
144149
let initial_state = match mutability {
145-
Mutability::Mut if ty_is_unpin => Permission::new_reserved(ty_is_freeze),
150+
Mutability::Mut if ty_is_unpin =>
151+
Permission::new_reserved(ty_is_freeze || is_protected),
146152
Mutability::Not if ty_is_freeze => Permission::new_frozen(),
147153
// Raw pointers never enter this function so they are not handled.
148154
// However raw pointers are not the only pointers that take the parent
@@ -151,7 +157,7 @@ impl<'tcx> NewPermission {
151157
_ => return None,
152158
};
153159

154-
let protector = (kind == RetagKind::FnEntry).then_some(ProtectorKind::StrongProtector);
160+
let protector = is_protected.then_some(ProtectorKind::StrongProtector);
155161
Some(Self { zero_size: false, initial_state, protector })
156162
}
157163

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ enum PermissionPriv {
2222
/// - foreign-read then child-write is UB due to `conflicted`,
2323
/// - child-write then foreign-read is UB since child-write will activate and then
2424
/// foreign-read disables a protected `Active`, which is UB.
25+
///
26+
/// Note: since the discovery of `tests/fail/tree_borrows/reservedim_spurious_write.rs`,
27+
/// `ty_is_freeze` does not strictly mean that the type has no interior mutability,
28+
/// it could be an interior mutable type that lost its interior mutability privileges
29+
/// when retagged with a protector.
2530
Reserved { ty_is_freeze: bool, conflicted: bool },
2631
/// represents: a unique pointer;
2732
/// allows: child reads, child writes;

src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Warning: this tree is indicative only. Some tags may have been hidden.
55
| RsM | └─┬──<TAG=base>
66
| RsM | ├─┬──<TAG=x>
77
| RsM | │ └─┬──<TAG=caller:x>
8-
| RsM | │ └────<TAG=callee:x> Strongly protected
8+
| Rs | │ └────<TAG=callee:x> Strongly protected
99
| RsM | └────<TAG=y, callee:y, caller:y>
1010
──────────────────────────────────────────────────
1111
error: Undefined Behavior: write access through <TAG> (y, callee:y, caller:y) at ALLOC[0x0] is forbidden
@@ -16,14 +16,14 @@ LL | *y = 1;
1616
|
1717
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
1818
= help: the accessed tag <TAG> (y, callee:y, caller:y) is foreign to the protected tag <TAG> (callee:x) (i.e., it is not a child)
19-
= help: this foreign write access would cause the protected tag <TAG> (callee:x) (currently Reserved (interior mutable)) to become Disabled
19+
= help: this foreign write access would cause the protected tag <TAG> (callee:x) (currently Reserved) to become Disabled
2020
= help: protected tags must never be Disabled
2121
help: the accessed tag <TAG> was created here
2222
--> $DIR/cell-protected-write.rs:LL:CC
2323
|
2424
LL | let y = (&mut *n).get();
2525
| ^^^^^^^^^
26-
help: the protected tag <TAG> was created here, in the initial state Reserved (interior mutable)
26+
help: the protected tag <TAG> was created here, in the initial state Reserved
2727
--> $DIR/cell-protected-write.rs:LL:CC
2828
|
2929
LL | unsafe fn write_second(x: &mut UnsafeCell<u8>, y: *mut u8) {

src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ fn example(spurious: bool) {
100100
let y = inner(unsafe { &mut *(ptr.0 as *mut Cell<u8>).wrapping_add(1) }, b.clone());
101101
synchronized!(b, "ret x");
102102
synchronized!(b, "write y");
103-
unsafe { *y.wrapping_sub(1) = 13 }
103+
unsafe { *y.wrapping_sub(1) = 13 } //~ERROR: /write access through .* is forbidden/
104104
synchronized!(b, "end");
105105
});
106106

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
Without spurious write
2+
Thread 1 executing: start
3+
Thread 2 executing: start
4+
Thread 2 executing: retag x (&mut, protect)
5+
Thread 1 executing: retag x (&mut, protect)
6+
Thread 1 executing: [lazy] retag y (&mut, protect, IM)
7+
Thread 2 executing: [lazy] retag y (&mut, protect, IM)
8+
Thread 2 executing: spurious write x
9+
Thread 1 executing: spurious write x (skipped)
10+
Thread 1 executing: ret y
11+
Thread 2 executing: ret y
12+
Thread 2 executing: ret x
13+
Thread 1 executing: ret x
14+
Thread 1 executing: write y
15+
Thread 2 executing: write y
16+
error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
17+
--> $DIR/reservedim_spurious_write.rs:LL:CC
18+
|
19+
LL | unsafe { *y.wrapping_sub(1) = 13 }
20+
| ^^^^^^^^^^^^^^^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
21+
|
22+
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
23+
= help: the accessed tag <TAG> has state Disabled which forbids this child write access
24+
help: the accessed tag <TAG> was created here, in the initial state Reserved
25+
--> $DIR/reservedim_spurious_write.rs:LL:CC
26+
|
27+
LL | fn inner(y: &mut Cell<u8>, b: IdxBarrier) -> *mut u8 {
28+
| ^
29+
help: the accessed tag <TAG> later transitioned to Disabled due to a protector release (acting as a foreign write access) on every location previously accessed by this tag
30+
--> $DIR/reservedim_spurious_write.rs:LL:CC
31+
|
32+
LL | }
33+
| ^
34+
= help: this transition corresponds to a loss of read and write permissions
35+
= note: BACKTRACE (of the first span) on thread `unnamed-ID`:
36+
= note: inside closure at $DIR/reservedim_spurious_write.rs:LL:CC
37+
38+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
39+
40+
error: aborting due to 1 previous error
41+

src/tools/miri/tests/pass/tree_borrows/reserved.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Warning: this tree is indicative only. Some tags may have been hidden.
66
| RsM | └─┬──<TAG=base>
77
| RsM | ├─┬──<TAG=x>
88
| RsM | │ └─┬──<TAG=caller:x>
9-
| RsCM| │ └────<TAG=callee:x>
9+
| RsC | │ └────<TAG=callee:x>
1010
| RsM | └────<TAG=y, caller:y, callee:y>
1111
──────────────────────────────────────────────────
1212
[interior mut] Foreign Read: Re* -> Re*

0 commit comments

Comments
 (0)