From 060a3a4bc11b5129fdd4e4989e3631169f303e46 Mon Sep 17 00:00:00 2001 From: NextTurn <45985406+NextTurn@users.noreply.github.com> Date: Mon, 14 Jan 2019 00:00:00 +0800 Subject: [PATCH] Raise noncontinuable exception when aborting on earlier Windows versions --- library/panic_abort/src/c.rs | 35 +++++++++++++++++++++ library/panic_abort/src/lib.rs | 50 ++++++++++++++++++------------ library/std/src/sys/windows/c.rs | 46 +++++++++++++++++++-------- library/std/src/sys/windows/mod.rs | 46 ++++++++++++++++++--------- 4 files changed, 129 insertions(+), 48 deletions(-) create mode 100644 library/panic_abort/src/c.rs diff --git a/library/panic_abort/src/c.rs b/library/panic_abort/src/c.rs new file mode 100644 index 0000000000000..fa55afae44592 --- /dev/null +++ b/library/panic_abort/src/c.rs @@ -0,0 +1,35 @@ +#![allow(nonstandard_style)] + +use libc::{c_int, c_ulong, c_void}; + +pub type DWORD = c_ulong; +pub type BOOL = c_int; + +pub type LPVOID = *mut c_void; + +pub const FALSE: BOOL = 0; + +pub const PF_FASTFAIL_AVAILABLE: DWORD = 23; + +pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; + +#[repr(C)] +pub struct EXCEPTION_RECORD { + pub ExceptionCode: DWORD, + pub ExceptionFlags: DWORD, + pub ExceptionRecord: *mut EXCEPTION_RECORD, + pub ExceptionAddress: LPVOID, + pub NumberParameters: DWORD, + pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS], +} + +pub enum CONTEXT {} + +extern "system" { + pub fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL; + pub fn RaiseFailFastException( + pExceptionRecord: *const EXCEPTION_RECORD, + pContextRecord: *const CONTEXT, + dwFlags: DWORD, + ); +} diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 3b08a64b22d85..54d400043c746 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -21,6 +21,13 @@ use core::any::Any; +cfg_if::cfg_if! { + if #[cfg(windows)] { + use core::ptr; + mod c; + } +} + #[rustc_std_internal_symbol] #[allow(improper_ctypes_definitions)] pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) { @@ -48,28 +55,31 @@ pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { __rust_abort(); } } else if #[cfg(windows)] { - // On Windows, use the processor-specific __fastfail mechanism. In Windows 8 - // and later, this will terminate the process immediately without running any - // in-process exception handlers. In earlier versions of Windows, this - // sequence of instructions will be treated as an access violation, - // terminating the process but without necessarily bypassing all exception - // handlers. - // - // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail - // - // Note: this is the same implementation as in libstd's `abort_internal` + /// On Windows 8 and later versions, use the processor-specific `__fastfail` + /// mechanism. This will terminate the process immediately without running any + /// in-process exception handlers. + /// On Windows 7, use `RaiseFailFastException` to raise a noncontinuable exception + /// `STATUS_FAIL_FAST_EXCEPTION`. + /// On earlier versions of Windows, use `RaiseException` to raise the same + /// noncontinuable exception. + /// + /// This is the same implementation as in libstd's `abort_internal`. unsafe fn abort() -> ! { - const FAST_FAIL_FATAL_APP_EXIT: usize = 7; - cfg_if::cfg_if! { - if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); - } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { - asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); - } else if #[cfg(target_arch = "aarch64")] { - asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); - } else { - core::intrinsics::abort(); + if c::IsProcessorFeaturePresent(c::PF_FASTFAIL_AVAILABLE) != c::FALSE { + const FAST_FAIL_FATAL_APP_EXIT: usize = 7; + cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); + } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { + asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); + } else if #[cfg(target_arch = "aarch64")] { + asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); + } else { + core::intrinsics::abort(); + } } + } else { + c::RaiseFailFastException(ptr::null(), ptr::null(), 0); } core::intrinsics::unreachable(); } diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index f440442ca3062..bce8bf7aa814e 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -286,6 +286,12 @@ pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008; +pub const PF_FASTFAIL_AVAILABLE: DWORD = 23; + +pub const STATUS_FAIL_FAST_EXCEPTION: DWORD = 0xC0000602; + +pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1; + #[repr(C)] #[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { @@ -625,24 +631,25 @@ pub struct timeval { pub tv_usec: c_long, } +pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; + +#[repr(C)] +pub struct EXCEPTION_RECORD { + pub ExceptionCode: DWORD, + pub ExceptionFlags: DWORD, + pub ExceptionRecord: *mut EXCEPTION_RECORD, + pub ExceptionAddress: LPVOID, + pub NumberParameters: DWORD, + pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS], +} + +pub enum CONTEXT {} + // Functions forbidden when targeting UWP cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; - pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; - - #[repr(C)] - pub struct EXCEPTION_RECORD { - pub ExceptionCode: DWORD, - pub ExceptionFlags: DWORD, - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ExceptionAddress: LPVOID, - pub NumberParameters: DWORD, - pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] - } - - pub enum CONTEXT {} #[repr(C)] pub struct EXCEPTION_POINTERS { @@ -1027,6 +1034,19 @@ extern "system" { pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; + + pub fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL; + pub fn RaiseException( + dwExceptionCode: DWORD, + dwExceptionFlags: DWORD, + nNumberOfArguments: DWORD, + lpArguments: *const ULONG_PTR, + ); + pub fn RaiseFailFastException( + pExceptionRecord: *const EXCEPTION_RECORD, + pContextRecord: *const CONTEXT, + dwFlags: DWORD, + ); } // Functions that aren't available on every version of Windows that we support, diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 8178e6806b9b3..1a0779b66d475 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -300,26 +300,42 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { .unwrap_or(c::INFINITE) } -/// Use `__fastfail` to abort the process +/// On Windows 8 and later versions, use the processor-specific `__fastfail` +/// mechanism. This will terminate the process immediately without running any +/// in-process exception handlers. +/// On Windows 7, use `RaiseFailFastException` to raise a noncontinuable exception +/// `STATUS_FAIL_FAST_EXCEPTION`. +/// On earlier versions of Windows, use `RaiseException` to raise the same +/// noncontinuable exception. /// -/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See -/// that function for more information on `__fastfail` +/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. #[allow(unreachable_code)] pub fn abort_internal() -> ! { - const FAST_FAIL_FATAL_APP_EXIT: usize = 7; unsafe { - cfg_if::cfg_if! { - if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); - crate::intrinsics::unreachable(); - } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { - asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); - crate::intrinsics::unreachable(); - } else if #[cfg(target_arch = "aarch64")] { - asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); - crate::intrinsics::unreachable(); + if c::IsProcessorFeaturePresent(c::PF_FASTFAIL_AVAILABLE) != c::FALSE { + const FAST_FAIL_FATAL_APP_EXIT: usize = 7; + cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); + } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { + asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); + } else if #[cfg(target_arch = "aarch64")] { + asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); + } else { + crate::intrinsics::abort(); + } } + } else { + match compat::lookup("kernel32", "RaiseFailFastException") { + Some(..) => c::RaiseFailFastException(ptr::null(), ptr::null(), 0), + None => c::RaiseException( + c::STATUS_FAIL_FAST_EXCEPTION, + c::EXCEPTION_NONCONTINUABLE, + 0, + ptr::null(), + ), + }; } + crate::intrinsics::unreachable(); } - crate::intrinsics::abort(); }