Skip to content

Commit 3d6a3ed

Browse files
committed
Auto merge of #75364 - rylev:libpanic-abort-failfast, r=alexcrichton
Call into fastfail on abort in libpanic_abort on Windows x86(_64) This partially resolves #73215 though this is only for x86 targets. This code is directly lifted from [libstd](https://github.com/rust-lang/rust/blob/13290e83a6e20f3b408d177a9d64d8cf98fe4615/library/std/src/sys/windows/mod.rs#L315). `__fastfail` is the preferred way to abort a process on Windows as it will hook into debugger toolchains. Other platforms expose a `_rust_abort` symbol which wraps `std::sys::abort_internal`. This would also work on Windows, but is a slightly largely change as we'd need to make sure that the symbol is properly exposed to the linker. I'm inlining the call to the `__fastfail`, but the indirection through `rust_abort` might be a cleaner approach. A different instruction must be used on ARM architectures. I'd like to verify this works first before tackling ARM.
2 parents c30341d + b9b8b5c commit 3d6a3ed

File tree

2 files changed

+21
-18
lines changed

2 files changed

+21
-18
lines changed

library/panic_abort/src/lib.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#![feature(panic_runtime)]
1818
#![feature(staged_api)]
1919
#![feature(rustc_attrs)]
20+
#![feature(llvm_asm)]
2021

2122
use core::any::Any;
2223

@@ -26,16 +27,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen
2627
unreachable!()
2728
}
2829

29-
// "Leak" the payload and shim to the relevant abort on the platform in
30-
// question.
31-
//
32-
// For Unix we just use `abort` from libc as it'll trigger debuggers, core
33-
// dumps, etc, as one might expect. On Windows, however, the best option we have
34-
// is the `__fastfail` intrinsics, but that's unfortunately not defined in LLVM,
35-
// and the `RaiseFailFastException` function isn't available until Windows 7
36-
// which would break compat with XP. For now just use `intrinsics::abort` which
37-
// will kill us with an illegal instruction, which will do a good enough job for
38-
// now hopefully.
30+
// "Leak" the payload and shim to the relevant abort on the platform in question.
3931
#[rustc_std_internal_symbol]
4032
pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
4133
abort();
@@ -55,6 +47,21 @@ pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
5547
}
5648
__rust_abort();
5749
}
50+
} else if #[cfg(all(windows, any(target_arch = "x86", target_arch = "x86_64")))] {
51+
// On Windows, use the processor-specific __fastfail mechanism. In Windows 8
52+
// and later, this will terminate the process immediately without running any
53+
// in-process exception handlers. In earlier versions of Windows, this
54+
// sequence of instructions will be treated as an access violation,
55+
// terminating the process but without necessarily bypassing all exception
56+
// handlers.
57+
//
58+
// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
59+
//
60+
// Note: this is the same implementation as in libstd's `abort_internal`
61+
unsafe fn abort() -> ! {
62+
llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
63+
core::intrinsics::unreachable();
64+
}
5865
} else {
5966
unsafe fn abort() -> ! {
6067
core::intrinsics::abort();

library/std/src/sys/windows/mod.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,10 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
300300
.unwrap_or(c::INFINITE)
301301
}
302302

303-
// On Windows, use the processor-specific __fastfail mechanism. In Windows 8
304-
// and later, this will terminate the process immediately without running any
305-
// in-process exception handlers. In earlier versions of Windows, this
306-
// sequence of instructions will be treated as an access violation,
307-
// terminating the process but without necessarily bypassing all exception
308-
// handlers.
309-
//
310-
// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
303+
/// Use `__fastfail` to abort the process
304+
///
305+
/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See
306+
/// that function for more information on `__fastfail`
311307
#[allow(unreachable_code)]
312308
pub fn abort_internal() -> ! {
313309
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]

0 commit comments

Comments
 (0)