@@ -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,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 ! ( "\n thread '{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