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