make &mut !Unpin not dereferenceable
See https://github.com/rust-lang/unsafe-code-guidelines/issues/381 for discussion.
This commit is contained in:
parent
201ae73872
commit
ea541bc2ee
6 changed files with 48 additions and 67 deletions
|
@ -256,13 +256,16 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
|
|
||||||
// `Box` are not necessarily dereferenceable for the entire duration of the function as
|
// `Box` are not necessarily dereferenceable for the entire duration of the function as
|
||||||
// they can be deallocated at any time. Same for non-frozen shared references (see
|
// they can be deallocated at any time. Same for non-frozen shared references (see
|
||||||
// <https://github.com/rust-lang/rust/pull/98017>). If LLVM had a way to say
|
// <https://github.com/rust-lang/rust/pull/98017>), and for mutable references to
|
||||||
// "dereferenceable on entry" we could use it here.
|
// potentially self-referential types (see
|
||||||
|
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>). If LLVM had a way
|
||||||
|
// to say "dereferenceable on entry" we could use it here.
|
||||||
attrs.pointee_size = match kind {
|
attrs.pointee_size = match kind {
|
||||||
PointerKind::Box | PointerKind::SharedRef { frozen: false } => Size::ZERO,
|
PointerKind::Box
|
||||||
PointerKind::SharedRef { frozen: true } | PointerKind::MutableRef { .. } => {
|
| PointerKind::SharedRef { frozen: false }
|
||||||
pointee.size
|
| PointerKind::MutableRef { unpin: false } => Size::ZERO,
|
||||||
}
|
PointerKind::SharedRef { frozen: true }
|
||||||
|
| PointerKind::MutableRef { unpin: true } => pointee.size,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The aliasing rules for `Box<T>` are still not decided, but currently we emit
|
// The aliasing rules for `Box<T>` are still not decided, but currently we emit
|
||||||
|
|
|
@ -81,21 +81,18 @@ impl NewPermission {
|
||||||
protector: None,
|
protector: None,
|
||||||
}
|
}
|
||||||
} else if pointee.is_unpin(*cx.tcx, cx.param_env()) {
|
} else if pointee.is_unpin(*cx.tcx, cx.param_env()) {
|
||||||
// A regular full mutable reference.
|
// A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`.
|
||||||
NewPermission::Uniform {
|
NewPermission::Uniform {
|
||||||
perm: Permission::Unique,
|
perm: Permission::Unique,
|
||||||
access: Some(AccessKind::Write),
|
access: Some(AccessKind::Write),
|
||||||
protector,
|
protector,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// `!Unpin` dereferences do not get `noalias` nor `dereferenceable`.
|
||||||
NewPermission::Uniform {
|
NewPermission::Uniform {
|
||||||
perm: Permission::SharedReadWrite,
|
perm: Permission::SharedReadWrite,
|
||||||
// FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
|
|
||||||
// should do fake accesses here. But then we run into
|
|
||||||
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
|
|
||||||
// we don't do that.
|
|
||||||
access: None,
|
access: None,
|
||||||
protector,
|
protector: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +106,7 @@ impl NewPermission {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Ref(_, _pointee, Mutability::Not) => {
|
ty::Ref(_, _pointee, Mutability::Not) => {
|
||||||
|
// Shared references. If frozen, these get `noalias` and `dereferenceable`; otherwise neither.
|
||||||
NewPermission::FreezeSensitive {
|
NewPermission::FreezeSensitive {
|
||||||
freeze_perm: Permission::SharedReadOnly,
|
freeze_perm: Permission::SharedReadOnly,
|
||||||
freeze_access: Some(AccessKind::Read),
|
freeze_access: Some(AccessKind::Read),
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
//@error-pattern: /deallocating while item \[SharedReadWrite for .*\] is strongly protected/
|
|
||||||
use std::marker::PhantomPinned;
|
|
||||||
|
|
||||||
pub struct NotUnpin(i32, PhantomPinned);
|
|
||||||
|
|
||||||
fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
|
|
||||||
// `f` may mutate, but it may not deallocate!
|
|
||||||
f(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
|
|
||||||
let raw = x as *mut _;
|
|
||||||
drop(unsafe { Box::from_raw(raw) });
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
error: Undefined Behavior: deallocating while item [SharedReadWrite for <TAG>] is strongly protected by call ID
|
|
||||||
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
|
||||||
|
|
|
||||||
LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadWrite for <TAG>] is strongly protected by call ID
|
|
||||||
|
|
|
||||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
|
|
||||||
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
|
||||||
= note: BACKTRACE:
|
|
||||||
= note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
|
||||||
= note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
|
||||||
= note: inside `alloc::alloc::box_free::<NotUnpin, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
|
||||||
= note: inside `std::ptr::drop_in_place::<std::boxed::Box<NotUnpin>> - shim(Some(std::boxed::Box<NotUnpin>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
|
||||||
= note: inside `std::mem::drop::<std::boxed::Box<NotUnpin>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
|
|
||||||
note: inside closure
|
|
||||||
--> $DIR/deallocate_against_protector2.rs:LL:CC
|
|
||||||
|
|
|
||||||
LL | drop(unsafe { Box::from_raw(raw) });
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
= note: inside `<[closure@$DIR/deallocate_against_protector2.rs:LL:CC] as std::ops::FnOnce<(&mut NotUnpin,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC
|
|
||||||
note: inside `inner`
|
|
||||||
--> $DIR/deallocate_against_protector2.rs:LL:CC
|
|
||||||
|
|
|
||||||
LL | f(x)
|
|
||||||
| ^^^^
|
|
||||||
note: inside `main`
|
|
||||||
--> $DIR/deallocate_against_protector2.rs:LL:CC
|
|
||||||
|
|
|
||||||
LL | / inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
|
|
||||||
LL | | let raw = x as *mut _;
|
|
||||||
LL | | drop(unsafe { Box::from_raw(raw) });
|
|
||||||
LL | | });
|
|
||||||
| |______^
|
|
||||||
|
|
||||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ fn main() {
|
||||||
array_casts();
|
array_casts();
|
||||||
mut_below_shr();
|
mut_below_shr();
|
||||||
wide_raw_ptr_in_tuple();
|
wide_raw_ptr_in_tuple();
|
||||||
|
not_unpin_not_protected();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that reading from an `&mut` does, like reborrowing to `&`,
|
// Make sure that reading from an `&mut` does, like reborrowing to `&`,
|
||||||
|
@ -219,3 +220,22 @@ fn wide_raw_ptr_in_tuple() {
|
||||||
// Make sure the fn ptr part of the vtable is still fine.
|
// Make sure the fn ptr part of the vtable is still fine.
|
||||||
r.type_id();
|
r.type_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn not_unpin_not_protected() {
|
||||||
|
// `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
|
||||||
|
// don't add protectors. (We could, but until we have a better idea for where we want to go with
|
||||||
|
// the self-referntial-generator situation, it does not seem worth the potential trouble.)
|
||||||
|
use std::marker::PhantomPinned;
|
||||||
|
|
||||||
|
pub struct NotUnpin(i32, PhantomPinned);
|
||||||
|
|
||||||
|
fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
|
||||||
|
// `f` may mutate, but it may not deallocate!
|
||||||
|
f(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
|
||||||
|
let raw = x as *mut _;
|
||||||
|
drop(unsafe { Box::from_raw(raw) });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -85,6 +85,12 @@ pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
|
||||||
pub fn readonly_borrow(_: &i32) {
|
pub fn readonly_borrow(_: &i32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @readonly_borrow_ret()
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn readonly_borrow_ret() -> &'static i32 {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK: @static_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
|
// CHECK: @static_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
|
||||||
// static borrow may be captured
|
// static borrow may be captured
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -115,9 +121,17 @@ pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
|
||||||
pub fn mutable_borrow(_: &mut i32) {
|
pub fn mutable_borrow(_: &mut i32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @mutable_borrow_ret()
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef align 4 dereferenceable(4) %_1)
|
pub fn mutable_borrow_ret() -> &'static mut i32 {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef nonnull align 4 %_1)
|
||||||
// This one is *not* `noalias` because it might be self-referential.
|
// This one is *not* `noalias` because it might be self-referential.
|
||||||
|
// It is also not `dereferenceable` due to
|
||||||
|
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
|
||||||
pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
|
pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue