diff options
| author | Jakob Degen <jakob.e.degen@gmail.com> | 2022-11-04 00:05:15 -0700 |
|---|---|---|
| committer | Jakob Degen <jakob.e.degen@gmail.com> | 2022-12-21 14:59:55 -0800 |
| commit | 102040ce76d588c0605e29577cdf8307acb4bb10 (patch) | |
| tree | cd6c29968b02bf15005e50980fa63c4e56dd4177 | |
| parent | 49143814e145c711e9807fac6467c14090663796 (diff) | |
| download | rust-102040ce76d588c0605e29577cdf8307acb4bb10.tar.gz rust-102040ce76d588c0605e29577cdf8307acb4bb10.zip | |
Retag as FnEntry on `drop_in_place`
9 files changed, 192 insertions, 3 deletions
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f8b55c86287..aa89ff00381 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -176,7 +176,33 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) if ty.is_some() { // The first argument (index 0), but add 1 for the return value. - let dropee_ptr = Place::from(Local::new(1 + 0)); + let mut dropee_ptr = Place::from(Local::new(1 + 0)); + if tcx.sess.opts.unstable_opts.mir_emit_retag { + // We want to treat the function argument as if it was passed by `&mut`. As such, we + // generate + // ``` + // temp = &mut *arg; + // Retag(temp, FnEntry) + // ``` + // It's important that we do this first, before anything that depends on `dropee_ptr` + // has been put into the body. + let reborrow = Rvalue::Ref( + tcx.lifetimes.re_erased, + BorrowKind::Mut { allow_two_phase_borrow: false }, + tcx.mk_place_deref(dropee_ptr), + ); + let ref_ty = reborrow.ty(body.local_decls(), tcx); + dropee_ptr = body.local_decls.push(LocalDecl::new(ref_ty, span)).into(); + let new_statements = [ + StatementKind::Assign(Box::new((dropee_ptr, reborrow))), + StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)), + ]; + for s in new_statements { + body.basic_blocks_mut()[START_BLOCK] + .statements + .push(Statement { source_info, kind: s }); + } + } let patch = { let param_env = tcx.param_env_reveal_all_normalized(def_id); let mut elaborator = diff --git a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir index 14f297e948b..f495f147be3 100644 --- a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir +++ b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir @@ -3,11 +3,14 @@ fn std::ptr::drop_in_place(_1: *mut Test) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 let mut _2: &mut Test; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _3: &mut Test; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + let mut _4: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 bb0: { _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = <Test as Drop>::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + Retag([fn entry] _2); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _3 = &mut (*_2); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 + _4 = <Test as Drop>::drop(move _3) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'a> fn(&'a mut Test) {<Test as Drop>::drop}, val: Value(<ZST>) } diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.rs b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.rs new file mode 100644 index 00000000000..883361d05fc --- /dev/null +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.rs @@ -0,0 +1,27 @@ +//! Test that drop_in_place retags the entire place, +//! invalidating all aliases to it. + +// A zero-sized drop type -- the retagging of `fn drop` itself won't +// do anything (since it is zero-sized); we are entirely relying on the retagging +// in `drop_in_place` here. +#[repr(transparent)] +struct HasDrop; +impl Drop for HasDrop { + fn drop(&mut self) { + unsafe { + let _val = *P; + //~^ ERROR: /not granting access .* because that would remove .* which is protected/ + } + } +} + +static mut P: *mut u8 = core::ptr::null_mut(); + +fn main() { + unsafe { + let mut x = (HasDrop, 0u8); + let x = core::ptr::addr_of_mut!(x); + P = x.cast(); + core::ptr::drop_in_place(x); + } +} diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr new file mode 100644 index 00000000000..6d122ade477 --- /dev/null +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr @@ -0,0 +1,33 @@ +error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of call ID + --> $DIR/drop_in_place_protector.rs:LL:CC + | +LL | let _val = *P; + | ^^ not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is protected because it is an argument of 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 +help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x1] + --> $DIR/drop_in_place_protector.rs:LL:CC + | +LL | let x = core::ptr::addr_of_mut!(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: <TAG> is this argument + --> $DIR/drop_in_place_protector.rs:LL:CC + | +LL | core::ptr::drop_in_place(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: BACKTRACE: + = note: inside `<HasDrop as std::ops::Drop>::drop` at $DIR/drop_in_place_protector.rs:LL:CC + = note: inside `std::ptr::drop_in_place::<HasDrop> - shim(Some(HasDrop))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::drop_in_place::<(HasDrop, u8)> - shim(Some((HasDrop, u8)))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC +note: inside `main` at $DIR/drop_in_place_protector.rs:LL:CC + --> $DIR/drop_in_place_protector.rs:LL:CC + | +LL | core::ptr::drop_in_place(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `core::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.rs b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.rs new file mode 100644 index 00000000000..4cb870f1d97 --- /dev/null +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.rs @@ -0,0 +1,19 @@ +//! Test that drop_in_place mutably retags the entire place, +//! ensuring it is writeable + +//@error-pattern: /retag .* for Unique permission .* only grants SharedReadOnly permission/ + +#[repr(transparent)] +struct HasDrop; + +impl Drop for HasDrop { + fn drop(&mut self) {} +} + +fn main() { + unsafe { + let x = (0u8, HasDrop); + let x = core::ptr::addr_of!(x); + core::ptr::drop_in_place(x.cast_mut()); + } +} diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr new file mode 100644 index 00000000000..022b27d69b2 --- /dev/null +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr @@ -0,0 +1,29 @@ +error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + --> RUSTLIB/core/src/ptr/mod.rs:LL:CC + | +LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of FnEntry retag at ALLOC[0x0..0x1] + | + = 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 +help: <TAG> was created by a SharedReadOnly retag at offsets [0x0..0x1] + --> $DIR/drop_in_place_retag.rs:LL:CC + | +LL | let x = core::ptr::addr_of!(x); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: BACKTRACE: + = note: inside `std::ptr::drop_in_place::<(u8, HasDrop)> - shim(Some((u8, HasDrop)))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC +note: inside `main` at $DIR/drop_in_place_retag.rs:LL:CC + --> $DIR/drop_in_place_retag.rs:LL:CC + | +LL | core::ptr::drop_in_place(x.cast_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `core::ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs new file mode 100644 index 00000000000..cf3a558bb99 --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs @@ -0,0 +1,25 @@ +#[repr(transparent)] +struct HasDrop(u8); + +impl Drop for HasDrop { + fn drop(&mut self) {} +} + +#[repr(C, align(2))] +struct PartialDrop { + a: HasDrop, + b: u8, +} + +//@error-pattern: /alignment 2 is required/ +fn main() { + unsafe { + // Create an unaligned pointer + let mut x = [0_u16; 2]; + let p = core::ptr::addr_of_mut!(x).cast::<u8>(); + let p = p.add(1); + let p = p.cast::<PartialDrop>(); + + core::ptr::drop_in_place(p); + } +} diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr new file mode 100644 index 00000000000..1081964987c --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> RUSTLIB/core/src/ptr/mod.rs:LL:CC + | +LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `std::ptr::drop_in_place::<PartialDrop> - shim(Some(PartialDrop))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC +note: inside `main` at $DIR/drop_in_place.rs:LL:CC + --> $DIR/drop_in_place.rs:LL:CC + | +LL | core::ptr::drop_in_place(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/pass/drop_in_place_null.rs b/src/tools/miri/tests/pass/drop_in_place_null.rs new file mode 100644 index 00000000000..aab070b6975 --- /dev/null +++ b/src/tools/miri/tests/pass/drop_in_place_null.rs @@ -0,0 +1,7 @@ +// Make sure that dropping types with no drop glue is DB even for invalid pointers. + +fn main() { + unsafe { + core::ptr::drop_in_place::<u8>(core::ptr::null_mut()); + } +} |
