@@ -499,13 +499,40 @@ impl Builder {
499
499
let output_capture = crate :: io:: set_output_capture ( None ) ;
500
500
crate :: io:: set_output_capture ( output_capture. clone ( ) ) ;
501
501
502
+ // Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*.
503
+ // See <https://github.com/rust-lang/rust/issues/101983> for more details.
504
+ // To prevent leaks we use a wrapper that drops its contents.
505
+ #[ repr( transparent) ]
506
+ struct MaybeDangling < T > ( mem:: MaybeUninit < T > ) ;
507
+ impl < T > MaybeDangling < T > {
508
+ fn new ( x : T ) -> Self {
509
+ MaybeDangling ( mem:: MaybeUninit :: new ( x) )
510
+ }
511
+ fn into_inner ( self ) -> T {
512
+ // SAFETY: we are always initiailized.
513
+ let ret = unsafe { self . 0 . assume_init_read ( ) } ;
514
+ // Make sure we don't drop.
515
+ mem:: forget ( self ) ;
516
+ ret
517
+ }
518
+ }
519
+ impl < T > Drop for MaybeDangling < T > {
520
+ fn drop ( & mut self ) {
521
+ // SAFETY: we are always initiailized.
522
+ unsafe { self . 0 . assume_init_drop ( ) } ;
523
+ }
524
+ }
525
+
526
+ let f = MaybeDangling :: new ( f) ;
502
527
let main = move || {
503
528
if let Some ( name) = their_thread. cname ( ) {
504
529
imp:: Thread :: set_name ( name) ;
505
530
}
506
531
507
532
crate :: io:: set_output_capture ( output_capture) ;
508
533
534
+ // SAFETY: we constructed `f` initialized.
535
+ let f = f. into_inner ( ) ;
509
536
// SAFETY: the stack guard passed is the one for the current thread.
510
537
// This means the current thread's stack and the new thread's stack
511
538
// are properly set and protected from each other.
@@ -518,6 +545,12 @@ impl Builder {
518
545
// same `JoinInner` as this closure meaning the mutation will be
519
546
// safe (not modify it and affect a value far away).
520
547
unsafe { * their_packet. result . get ( ) = Some ( try_result) } ;
548
+ // Here `their_packet` gets dropped, and if this is the last `Arc` for that packet that
549
+ // will call `decrement_num_running_threads` and therefore signal that this thread is
550
+ // done.
551
+ drop ( their_packet) ;
552
+ // Here, the lifetime `'a` and even `'scope` can end. `main` keeps running for a bit
553
+ // after that before returning itself.
521
554
} ;
522
555
523
556
if let Some ( scope_data) = & my_packet. scope {
0 commit comments