about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-03-14 11:23:39 +0100
committerRalf Jung <post@ralfj.de>2020-03-14 11:24:11 +0100
commit9c5d8e9b520c12044c818dd3d48f02bcea075ec3 (patch)
tree784caf6fbc79840b3c726f0fe3d82bdd913ce445
parent62087439a46f09b6a6716fc25b4a032f3d76eb71 (diff)
downloadrust-9c5d8e9b520c12044c818dd3d48f02bcea075ec3.tar.gz
rust-9c5d8e9b520c12044c818dd3d48f02bcea075ec3.zip
adjust Miri interaction with panic runtime
-rw-r--r--src/libcore/intrinsics.rs8
-rw-r--r--src/libpanic_unwind/lib.rs35
-rw-r--r--src/libpanic_unwind/miri.rs20
3 files changed, 47 insertions, 16 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index c2f13047e54..d722406b82b 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1892,10 +1892,12 @@ extern "rust-intrinsic" {
     pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
 
     /// Internal hook used by Miri to implement unwinding.
-    /// Compiles to a NOP during non-Miri codegen.
+    /// ICEs when encountered during non-Miri codegen.
     ///
-    /// Perma-unstable: do not use
-    pub fn miri_start_panic(data: *mut (dyn crate::any::Any + crate::marker::Send)) -> ();
+    /// The `payload` ptr here will be exactly the one `do_catch` gets passed by `try`.
+    ///
+    /// Perma-unstable: do not use.
+    pub fn miri_start_panic(payload: *mut u8) -> !;
 }
 
 // Some functions are defined here because they accidentally got made
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index d6c33666938..c213b19d062 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -31,6 +31,9 @@
 #![panic_runtime]
 #![feature(panic_runtime)]
 
+// `real_imp` is unused with Miri, so silence warnings.
+#![cfg_attr(miri, allow(dead_code))]
+
 use alloc::boxed::Box;
 use core::any::Any;
 use core::panic::BoxMeUp;
@@ -38,25 +41,38 @@ use core::panic::BoxMeUp;
 cfg_if::cfg_if! {
     if #[cfg(target_os = "emscripten")] {
         #[path = "emcc.rs"]
-        mod imp;
+        mod real_imp;
     } else if #[cfg(target_arch = "wasm32")] {
         #[path = "dummy.rs"]
-        mod imp;
+        mod real_imp;
     } else if #[cfg(target_os = "hermit")] {
         #[path = "hermit.rs"]
-        mod imp;
+        mod real_imp;
     } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {
         #[path = "dummy.rs"]
-        mod imp;
+        mod real_imp;
     } else if #[cfg(target_env = "msvc")] {
         #[path = "seh.rs"]
-        mod imp;
+        mod real_imp;
     } else {
         // Rust runtime's startup objects depend on these symbols, so make them public.
         #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
-        pub use imp::eh_frame_registry::*;
+        pub use real_imp::eh_frame_registry::*;
         #[path = "gcc.rs"]
+        mod real_imp;
+    }
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(miri)] {
+        // Use the Miri runtime.
+        // We still need to also load the normal runtime above, as rustc expects certain lang
+        // items from there to be defined.
+        #[path = "miri.rs"]
         mod imp;
+    } else {
+        // Use the real runtime.
+        use real_imp as imp;
     }
 }
 
@@ -81,12 +97,5 @@ pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 {
     let payload = payload as *mut &mut dyn BoxMeUp;
     let payload = (*payload).take_box();
 
-    // Miri panic support: cfg'd out of normal builds just to be sure.
-    // When going through normal codegen, `miri_start_panic` is a NOP, so the
-    // Miri-enabled sysroot still supports normal unwinding. But when executed in
-    // Miri, this line initiates unwinding.
-    #[cfg(miri)]
-    core::intrinsics::miri_start_panic(payload);
-
     imp::panic(Box::from_raw(payload))
 }
diff --git a/src/libpanic_unwind/miri.rs b/src/libpanic_unwind/miri.rs
new file mode 100644
index 00000000000..5f44b98566f
--- /dev/null
+++ b/src/libpanic_unwind/miri.rs
@@ -0,0 +1,20 @@
+//! Unwinding panics for Miri.
+use core::any::Any;
+use alloc::boxed::Box;
+
+// The type of the payload that the Miri engine propagates through unwinding for us.
+// Must be pointer-sized.
+type Payload = Box<Box<dyn Any + Send>>;
+
+pub unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 {
+    // The payload we pass to `miri_start_panic` will be exactly the argument we get
+    // in `cleanup` below. So we just box it up once, to get something pointer-sized.
+    let payload_box: Payload = Box::new(payload);
+    core::intrinsics::miri_start_panic(Box::into_raw(payload_box) as *mut u8)
+}
+
+pub unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> {
+    // Recover the underlying `Box`.
+    let payload_box: Payload = Box::from_raw(payload_box as *mut _);
+    *payload_box
+}