Skip to content

Commit 7ed495a

Browse files
committed
Add stack overflow handler for cygwin
1 parent 9c67cec commit 7ed495a

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

library/std/src/sys/pal/unix/stack_overflow.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ mod imp {
585585
target_os = "openbsd",
586586
target_os = "solaris",
587587
target_os = "illumos",
588+
target_os = "cygwin",
588589
)))]
589590
mod imp {
590591
pub unsafe fn init() {}
@@ -597,3 +598,86 @@ mod imp {
597598

598599
pub unsafe fn drop_handler(_data: *mut libc::c_void) {}
599600
}
601+
602+
#[cfg(target_os = "cygwin")]
603+
mod imp {
604+
mod c {
605+
pub type PVECTORED_EXCEPTION_HANDLER =
606+
Option<unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32>;
607+
pub type NTSTATUS = i32;
608+
pub type BOOL = i32;
609+
610+
extern "system" {
611+
pub fn AddVectoredExceptionHandler(first: u32, handler: PVECTORED_EXCEPTION_HANDLER) -> *mut core::ffi::c_void;
612+
pub fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL;
613+
}
614+
615+
pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _;
616+
pub const EXCEPTION_CONTINUE_SEARCH: i32 = 1i32;
617+
618+
#[repr(C)]
619+
#[derive(Clone, Copy)]
620+
pub struct EXCEPTION_POINTERS {
621+
pub ExceptionRecord: *mut EXCEPTION_RECORD,
622+
// We don't need this field here
623+
// pub Context: *mut CONTEXT,
624+
}
625+
#[repr(C)]
626+
#[derive(Clone, Copy)]
627+
pub struct EXCEPTION_RECORD {
628+
pub ExceptionCode: NTSTATUS,
629+
pub ExceptionFlags: u32,
630+
pub ExceptionRecord: *mut EXCEPTION_RECORD,
631+
pub ExceptionAddress: *mut core::ffi::c_void,
632+
pub NumberParameters: u32,
633+
pub ExceptionInformation: [usize; 15],
634+
}
635+
}
636+
637+
/// Reserve stack space for use in stack overflow exceptions.
638+
fn reserve_stack() {
639+
let result = unsafe { c::SetThreadStackGuarantee(&mut 0x5000) };
640+
// Reserving stack space is not critical so we allow it to fail in the released build of libstd.
641+
// We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
642+
debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
643+
}
644+
645+
unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 {
646+
// SAFETY: It's up to the caller (which in this case is the OS) to ensure that `ExceptionInfo` is valid.
647+
unsafe {
648+
let rec = &(*(*ExceptionInfo).ExceptionRecord);
649+
let code = rec.ExceptionCode;
650+
651+
if code == c::EXCEPTION_STACK_OVERFLOW {
652+
crate::thread::with_current_name(|name| {
653+
let name = name.unwrap_or("<unknown>");
654+
rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
655+
});
656+
}
657+
c::EXCEPTION_CONTINUE_SEARCH
658+
}
659+
}
660+
661+
pub unsafe fn init() {
662+
// SAFETY: `vectored_handler` has the correct ABI and is safe to call during exception handling.
663+
unsafe {
664+
let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
665+
// Similar to the above, adding the stack overflow handler is allowed to fail
666+
// but a debug assert is used so CI will still test that it normally works.
667+
debug_assert!(!result.is_null(), "failed to install exception handler");
668+
}
669+
// Set the thread stack guarantee for the main thread.
670+
reserve_stack();
671+
}
672+
673+
pub unsafe fn cleanup() {}
674+
675+
pub unsafe fn make_handler(main_thread: bool) -> super::Handler {
676+
if !main_thread {
677+
reserve_stack();
678+
}
679+
super::Handler::null()
680+
}
681+
682+
pub unsafe fn drop_handler(_data: *mut libc::c_void) {}
683+
}

0 commit comments

Comments
 (0)