Skip to content

Commit 060a3a4

Browse files
committed
Raise noncontinuable exception when aborting on earlier Windows versions
1 parent e88e908 commit 060a3a4

File tree

4 files changed

+129
-48
lines changed

4 files changed

+129
-48
lines changed

library/panic_abort/src/c.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#![allow(nonstandard_style)]
2+
3+
use libc::{c_int, c_ulong, c_void};
4+
5+
pub type DWORD = c_ulong;
6+
pub type BOOL = c_int;
7+
8+
pub type LPVOID = *mut c_void;
9+
10+
pub const FALSE: BOOL = 0;
11+
12+
pub const PF_FASTFAIL_AVAILABLE: DWORD = 23;
13+
14+
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
15+
16+
#[repr(C)]
17+
pub struct EXCEPTION_RECORD {
18+
pub ExceptionCode: DWORD,
19+
pub ExceptionFlags: DWORD,
20+
pub ExceptionRecord: *mut EXCEPTION_RECORD,
21+
pub ExceptionAddress: LPVOID,
22+
pub NumberParameters: DWORD,
23+
pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS],
24+
}
25+
26+
pub enum CONTEXT {}
27+
28+
extern "system" {
29+
pub fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL;
30+
pub fn RaiseFailFastException(
31+
pExceptionRecord: *const EXCEPTION_RECORD,
32+
pContextRecord: *const CONTEXT,
33+
dwFlags: DWORD,
34+
);
35+
}

library/panic_abort/src/lib.rs

+30-20
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121

2222
use core::any::Any;
2323

24+
cfg_if::cfg_if! {
25+
if #[cfg(windows)] {
26+
use core::ptr;
27+
mod c;
28+
}
29+
}
30+
2431
#[rustc_std_internal_symbol]
2532
#[allow(improper_ctypes_definitions)]
2633
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 {
4855
__rust_abort();
4956
}
5057
} else if #[cfg(windows)] {
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`
58+
/// On Windows 8 and later versions, use the processor-specific `__fastfail`
59+
/// mechanism. This will terminate the process immediately without running any
60+
/// in-process exception handlers.
61+
/// On Windows 7, use `RaiseFailFastException` to raise a noncontinuable exception
62+
/// `STATUS_FAIL_FAST_EXCEPTION`.
63+
/// On earlier versions of Windows, use `RaiseException` to raise the same
64+
/// noncontinuable exception.
65+
///
66+
/// This is the same implementation as in libstd's `abort_internal`.
6167
unsafe fn abort() -> ! {
62-
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
63-
cfg_if::cfg_if! {
64-
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
65-
asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
66-
} else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
67-
asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
68-
} else if #[cfg(target_arch = "aarch64")] {
69-
asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
70-
} else {
71-
core::intrinsics::abort();
68+
if c::IsProcessorFeaturePresent(c::PF_FASTFAIL_AVAILABLE) != c::FALSE {
69+
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
70+
cfg_if::cfg_if! {
71+
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
72+
asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
73+
} else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
74+
asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
75+
} else if #[cfg(target_arch = "aarch64")] {
76+
asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
77+
} else {
78+
core::intrinsics::abort();
79+
}
7280
}
81+
} else {
82+
c::RaiseFailFastException(ptr::null(), ptr::null(), 0);
7383
}
7484
core::intrinsics::unreachable();
7585
}

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

+33-13
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,12 @@ pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
286286

287287
pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
288288

289+
pub const PF_FASTFAIL_AVAILABLE: DWORD = 23;
290+
291+
pub const STATUS_FAIL_FAST_EXCEPTION: DWORD = 0xC0000602;
292+
293+
pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1;
294+
289295
#[repr(C)]
290296
#[cfg(not(target_pointer_width = "64"))]
291297
pub struct WSADATA {
@@ -625,24 +631,25 @@ pub struct timeval {
625631
pub tv_usec: c_long,
626632
}
627633

634+
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
635+
636+
#[repr(C)]
637+
pub struct EXCEPTION_RECORD {
638+
pub ExceptionCode: DWORD,
639+
pub ExceptionFlags: DWORD,
640+
pub ExceptionRecord: *mut EXCEPTION_RECORD,
641+
pub ExceptionAddress: LPVOID,
642+
pub NumberParameters: DWORD,
643+
pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS],
644+
}
645+
646+
pub enum CONTEXT {}
647+
628648
// Functions forbidden when targeting UWP
629649
cfg_if::cfg_if! {
630650
if #[cfg(not(target_vendor = "uwp"))] {
631651
pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
632652
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
633-
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
634-
635-
#[repr(C)]
636-
pub struct EXCEPTION_RECORD {
637-
pub ExceptionCode: DWORD,
638-
pub ExceptionFlags: DWORD,
639-
pub ExceptionRecord: *mut EXCEPTION_RECORD,
640-
pub ExceptionAddress: LPVOID,
641-
pub NumberParameters: DWORD,
642-
pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
643-
}
644-
645-
pub enum CONTEXT {}
646653

647654
#[repr(C)]
648655
pub struct EXCEPTION_POINTERS {
@@ -1027,6 +1034,19 @@ extern "system" {
10271034
pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
10281035
pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
10291036
pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
1037+
1038+
pub fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL;
1039+
pub fn RaiseException(
1040+
dwExceptionCode: DWORD,
1041+
dwExceptionFlags: DWORD,
1042+
nNumberOfArguments: DWORD,
1043+
lpArguments: *const ULONG_PTR,
1044+
);
1045+
pub fn RaiseFailFastException(
1046+
pExceptionRecord: *const EXCEPTION_RECORD,
1047+
pContextRecord: *const CONTEXT,
1048+
dwFlags: DWORD,
1049+
);
10301050
}
10311051

10321052
// Functions that aren't available on every version of Windows that we support,

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

+31-15
Original file line numberDiff line numberDiff line change
@@ -300,26 +300,42 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
300300
.unwrap_or(c::INFINITE)
301301
}
302302

303-
/// Use `__fastfail` to abort the process
303+
/// On Windows 8 and later versions, use the processor-specific `__fastfail`
304+
/// mechanism. This will terminate the process immediately without running any
305+
/// in-process exception handlers.
306+
/// On Windows 7, use `RaiseFailFastException` to raise a noncontinuable exception
307+
/// `STATUS_FAIL_FAST_EXCEPTION`.
308+
/// On earlier versions of Windows, use `RaiseException` to raise the same
309+
/// noncontinuable exception.
304310
///
305-
/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See
306-
/// that function for more information on `__fastfail`
311+
/// This is the same implementation as in libpanic_abort's `__rust_start_panic`.
307312
#[allow(unreachable_code)]
308313
pub fn abort_internal() -> ! {
309-
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
310314
unsafe {
311-
cfg_if::cfg_if! {
312-
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
313-
asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
314-
crate::intrinsics::unreachable();
315-
} else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
316-
asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
317-
crate::intrinsics::unreachable();
318-
} else if #[cfg(target_arch = "aarch64")] {
319-
asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
320-
crate::intrinsics::unreachable();
315+
if c::IsProcessorFeaturePresent(c::PF_FASTFAIL_AVAILABLE) != c::FALSE {
316+
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
317+
cfg_if::cfg_if! {
318+
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
319+
asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
320+
} else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
321+
asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
322+
} else if #[cfg(target_arch = "aarch64")] {
323+
asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
324+
} else {
325+
crate::intrinsics::abort();
326+
}
321327
}
328+
} else {
329+
match compat::lookup("kernel32", "RaiseFailFastException") {
330+
Some(..) => c::RaiseFailFastException(ptr::null(), ptr::null(), 0),
331+
None => c::RaiseException(
332+
c::STATUS_FAIL_FAST_EXCEPTION,
333+
c::EXCEPTION_NONCONTINUABLE,
334+
0,
335+
ptr::null(),
336+
),
337+
};
322338
}
339+
crate::intrinsics::unreachable();
323340
}
324-
crate::intrinsics::abort();
325341
}

0 commit comments

Comments
 (0)