@@ -366,6 +366,35 @@ pub mod panic_count {
366
366
} ) ;
367
367
}
368
368
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
+
369
398
pub fn set_always_abort ( ) {
370
399
GLOBAL_PANIC_COUNT . fetch_or ( ALWAYS_ABORT_FLAG , Ordering :: Relaxed ) ;
371
400
}
@@ -453,7 +482,12 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
453
482
// - `do_catch`, the second argument, can be called with the `data_ptr` as well.
454
483
// See their safety preconditions for more information
455
484
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 {
457
491
Ok ( ManuallyDrop :: into_inner ( data. r ) )
458
492
} else {
459
493
Err ( ManuallyDrop :: into_inner ( data. p ) )
@@ -705,10 +739,10 @@ fn rust_panic_with_hook(
705
739
}
706
740
707
741
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 .
712
746
rtprintpanic ! ( "thread panicked while panicking. aborting.\n " ) ;
713
747
crate :: sys:: abort_internal ( ) ;
714
748
}
0 commit comments