@@ -366,6 +366,35 @@ pub mod panic_count {
366366 } ) ;
367367 }
368368
369+ // Decrease the panic count only if the thread is already panicking.
370+ // Allows running code nested within a wind that may itself unwind.
371+ #[ inline]
372+ #[ must_use]
373+ pub fn try_decrease ( ) -> bool {
374+ if GLOBAL_PANIC_COUNT . load ( Ordering :: Relaxed ) & !ALWAYS_ABORT_FLAG == 0 {
375+ // Fast path: see count_is_zero.
376+ false
377+ } else {
378+ try_decrease_slow_path ( )
379+ }
380+ }
381+
382+ // We consider unwinding to be rare, so mark this function as cold.
383+ // However, leave the inlining decision entirely to the optimizer.
384+ #[ cold]
385+ fn try_decrease_slow_path ( ) -> bool {
386+ LOCAL_PANIC_COUNT . with ( |c| {
387+ let panic_count = c. get ( ) ;
388+ if panic_count > 0 {
389+ GLOBAL_PANIC_COUNT . fetch_sub ( 1 , Ordering :: Relaxed ) ;
390+ c. set ( panic_count - 1 ) ;
391+ true
392+ } else {
393+ false
394+ }
395+ } )
396+ }
397+
369398 pub fn set_always_abort ( ) {
370399 GLOBAL_PANIC_COUNT . fetch_or ( ALWAYS_ABORT_FLAG , Ordering :: Relaxed ) ;
371400 }
@@ -453,7 +482,12 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
453482 // - `do_catch`, the second argument, can be called with the `data_ptr` as well.
454483 // See their safety preconditions for more information
455484 unsafe {
456- return if intrinsics:: r#try ( do_call :: < F , R > , data_ptr, do_catch :: < F , R > ) == 0 {
485+ let is_panicking = panic_count:: try_decrease ( ) ;
486+ let success = intrinsics:: r#try ( do_call :: < F , R > , data_ptr, do_catch :: < F , R > ) == 0 ;
487+ if is_panicking {
488+ panic_count:: increase ( ) ;
489+ }
490+ return if success {
457491 Ok ( ManuallyDrop :: into_inner ( data. r ) )
458492 } else {
459493 Err ( ManuallyDrop :: into_inner ( data. p ) )
@@ -705,10 +739,10 @@ fn rust_panic_with_hook(
705739 }
706740
707741 if panics > 1 || !can_unwind {
708- // If a thread panics while it's already unwinding then we
709- // have limited options. Currently our preference is to
710- // just abort. In the future we may consider resuming
711- // unwinding or otherwise exiting the thread cleanly .
742+ // If the thread was already panicking, then the closest catch_unwind
743+ // has already been claimed by the existing panic. If a new catch_unwind
744+ // had been registered, it would have cleared the panicking flag. Since
745+ // this panic is not well-nested, we just abort the process .
712746 rtprintpanic ! ( "thread panicked while panicking. aborting.\n " ) ;
713747 crate :: sys:: abort_internal ( ) ;
714748 }
0 commit comments