Skip to content

Commit ea541bc

Browse files
committed
make &mut !Unpin not dereferenceable
See rust-lang/unsafe-code-guidelines#381 for discussion.
1 parent 201ae73 commit ea541bc

File tree

6 files changed

+48
-67
lines changed

6 files changed

+48
-67
lines changed

compiler/rustc_ty_utils/src/abi.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,16 @@ fn adjust_for_rust_scalar<'tcx>(
256256

257257
// `Box` are not necessarily dereferenceable for the entire duration of the function as
258258
// they can be deallocated at any time. Same for non-frozen shared references (see
259-
// <https://github.com/rust-lang/rust/pull/98017>). If LLVM had a way to say
260-
// "dereferenceable on entry" we could use it here.
259+
// <https://github.com/rust-lang/rust/pull/98017>), and for mutable references to
260+
// potentially self-referential types (see
261+
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>). If LLVM had a way
262+
// to say "dereferenceable on entry" we could use it here.
261263
attrs.pointee_size = match kind {
262-
PointerKind::Box | PointerKind::SharedRef { frozen: false } => Size::ZERO,
263-
PointerKind::SharedRef { frozen: true } | PointerKind::MutableRef { .. } => {
264-
pointee.size
265-
}
264+
PointerKind::Box
265+
| PointerKind::SharedRef { frozen: false }
266+
| PointerKind::MutableRef { unpin: false } => Size::ZERO,
267+
PointerKind::SharedRef { frozen: true }
268+
| PointerKind::MutableRef { unpin: true } => pointee.size,
266269
};
267270

268271
// The aliasing rules for `Box<T>` are still not decided, but currently we emit

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

+4-6
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,18 @@ impl NewPermission {
8181
protector: None,
8282
}
8383
} else if pointee.is_unpin(*cx.tcx, cx.param_env()) {
84-
// A regular full mutable reference.
84+
// A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`.
8585
NewPermission::Uniform {
8686
perm: Permission::Unique,
8787
access: Some(AccessKind::Write),
8888
protector,
8989
}
9090
} else {
91+
// `!Unpin` dereferences do not get `noalias` nor `dereferenceable`.
9192
NewPermission::Uniform {
9293
perm: Permission::SharedReadWrite,
93-
// FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
94-
// should do fake accesses here. But then we run into
95-
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
96-
// we don't do that.
9794
access: None,
98-
protector,
95+
protector: None,
9996
}
10097
}
10198
}
@@ -109,6 +106,7 @@ impl NewPermission {
109106
}
110107
}
111108
ty::Ref(_, _pointee, Mutability::Not) => {
109+
// Shared references. If frozen, these get `noalias` and `dereferenceable`; otherwise neither.
112110
NewPermission::FreezeSensitive {
113111
freeze_perm: Permission::SharedReadOnly,
114112
freeze_access: Some(AccessKind::Read),

src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.rs

-16
This file was deleted.

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

-38
This file was deleted.

src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs

+20
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ fn main() {
1919
array_casts();
2020
mut_below_shr();
2121
wide_raw_ptr_in_tuple();
22+
not_unpin_not_protected();
2223
}
2324

2425
// Make sure that reading from an `&mut` does, like reborrowing to `&`,
@@ -219,3 +220,22 @@ fn wide_raw_ptr_in_tuple() {
219220
// Make sure the fn ptr part of the vtable is still fine.
220221
r.type_id();
221222
}
223+
224+
fn not_unpin_not_protected() {
225+
// `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
226+
// don't add protectors. (We could, but until we have a better idea for where we want to go with
227+
// the self-referntial-generator situation, it does not seem worth the potential trouble.)
228+
use std::marker::PhantomPinned;
229+
230+
pub struct NotUnpin(i32, PhantomPinned);
231+
232+
fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
233+
// `f` may mutate, but it may not deallocate!
234+
f(x)
235+
}
236+
237+
inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
238+
let raw = x as *mut _;
239+
drop(unsafe { Box::from_raw(raw) });
240+
});
241+
}

tests/codegen/function-arguments.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
8585
pub fn readonly_borrow(_: &i32) {
8686
}
8787

88+
// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @readonly_borrow_ret()
89+
#[no_mangle]
90+
pub fn readonly_borrow_ret() -> &'static i32 {
91+
loop {}
92+
}
93+
8894
// CHECK: @static_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
8995
// static borrow may be captured
9096
#[no_mangle]
@@ -115,9 +121,17 @@ pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
115121
pub fn mutable_borrow(_: &mut i32) {
116122
}
117123

124+
// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @mutable_borrow_ret()
125+
#[no_mangle]
126+
pub fn mutable_borrow_ret() -> &'static mut i32 {
127+
loop {}
128+
}
129+
118130
#[no_mangle]
119-
// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef align 4 dereferenceable(4) %_1)
131+
// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef nonnull align 4 %_1)
120132
// This one is *not* `noalias` because it might be self-referential.
133+
// It is also not `dereferenceable` due to
134+
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
121135
pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
122136
}
123137

0 commit comments

Comments
 (0)