about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakob Degen <jakob.e.degen@gmail.com>2022-11-04 00:05:15 -0700
committerJakob Degen <jakob.e.degen@gmail.com>2022-12-21 14:59:55 -0800
commit102040ce76d588c0605e29577cdf8307acb4bb10 (patch)
treecd6c29968b02bf15005e50980fa63c4e56dd4177
parent49143814e145c711e9807fac6467c14090663796 (diff)
downloadrust-102040ce76d588c0605e29577cdf8307acb4bb10.tar.gz
rust-102040ce76d588c0605e29577cdf8307acb4bb10.zip
Retag as FnEntry on `drop_in_place`
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs28
-rw-r--r--src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir7
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.rs27
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/drop_in_place_protector.stderr33
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.rs19
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr29
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs25
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr20
-rw-r--r--src/tools/miri/tests/pass/drop_in_place_null.rs7
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());
+    }
+}