Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise noncontinuable exception when aborting on earlier Windows versions #76203

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions library/panic_abort/src/c.rs
Original file line number Diff line number Diff line change
@@ -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,
);
}
50 changes: 30 additions & 20 deletions library/panic_abort/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there no fallback to RaiseException here?

}
core::intrinsics::unreachable();
}
Expand Down
46 changes: 33 additions & 13 deletions library/std/src/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
46 changes: 31 additions & 15 deletions library/std/src/sys/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Copy link
Member

@m-ou-se m-ou-se Oct 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you put RaiseFailFastException in the compat_fn!{} block in c.rs, you can use c::RaiseFailFastException::is_available() here (since #76979).

Some(..) => c::RaiseFailFastException(ptr::null(), ptr::null(), 0),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will cause a runtime missing symbol error on older Windows versions here since you are directly linking to the RaiseFailFastException symbol.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RaiseFailFastException requires Windows 7 so we'd need a fallback for XP/Vista.

None => c::RaiseException(
c::STATUS_FAIL_FAST_EXCEPTION,
c::EXCEPTION_NONCONTINUABLE,
0,
ptr::null(),
),
};
}
crate::intrinsics::unreachable();
}
crate::intrinsics::abort();
}