@@ -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,89 @@ 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
+ 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