@@ -585,6 +585,7 @@ mod imp {
585
585
target_os = "openbsd" ,
586
586
target_os = "solaris" ,
587
587
target_os = "illumos" ,
588
+ target_os = "cygwin" ,
588
589
) ) ) ]
589
590
mod imp {
590
591
pub unsafe fn init ( ) { }
@@ -597,3 +598,86 @@ mod imp {
597
598
598
599
pub unsafe fn drop_handler ( _data : * mut libc:: c_void ) { }
599
600
}
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