77 target_os = "aix" ,
88) ) ) ]
99use crate :: ffi:: CStr ;
10- use crate :: mem:: { self , ManuallyDrop } ;
10+ use crate :: mem:: { self , DropGuard , ManuallyDrop } ;
1111use crate :: num:: NonZero ;
1212#[ cfg( all( target_os = "linux" , target_env = "gnu" ) ) ]
1313use crate :: sys:: weak:: dlsym;
@@ -52,10 +52,13 @@ impl Thread {
5252 name : Option < & str > ,
5353 f : Box < dyn FnOnce ( ) > ,
5454 ) -> io:: Result < Thread > {
55- let data = Box :: into_raw ( Box :: new ( ThreadData { name : name. map ( Box :: from) , f } ) ) ;
56- let mut native : libc :: pthread_t = mem :: zeroed ( ) ;
55+ let data = Box :: new ( ThreadData { name : name. map ( Box :: from) , f } ) ;
56+
5757 let mut attr: mem:: MaybeUninit < libc:: pthread_attr_t > = mem:: MaybeUninit :: uninit ( ) ;
5858 assert_eq ! ( libc:: pthread_attr_init( attr. as_mut_ptr( ) ) , 0 ) ;
59+ let mut attr = DropGuard :: new ( & mut attr, |attr| {
60+ assert_eq ! ( libc:: pthread_attr_destroy( attr. as_mut_ptr( ) ) , 0 )
61+ } ) ;
5962
6063 #[ cfg( any( target_os = "espidf" , target_os = "nuttx" ) ) ]
6164 if stack > 0 {
@@ -90,8 +93,6 @@ impl Thread {
9093 // on the stack size, in which case we can only gracefully return
9194 // an error here.
9295 if libc:: pthread_attr_setstacksize ( attr. as_mut_ptr ( ) , stack_size) != 0 {
93- assert_eq ! ( libc:: pthread_attr_destroy( attr. as_mut_ptr( ) ) , 0 ) ;
94- drop ( Box :: from_raw ( data) ) ;
9596 return Err ( io:: const_error!(
9697 io:: ErrorKind :: InvalidInput ,
9798 "invalid stack size"
@@ -101,19 +102,16 @@ impl Thread {
101102 } ;
102103 }
103104
105+ let data = Box :: into_raw ( data) ;
106+ let mut native: libc:: pthread_t = mem:: zeroed ( ) ;
104107 let ret = libc:: pthread_create ( & mut native, attr. as_ptr ( ) , thread_start, data as * mut _ ) ;
105- // Note: if the thread creation fails and this assert fails, then p will
106- // be leaked. However, an alternative design could cause double-free
107- // which is clearly worse.
108- assert_eq ! ( libc:: pthread_attr_destroy( attr. as_mut_ptr( ) ) , 0 ) ;
109-
110- return if ret != 0 {
111- // The thread failed to start and as a result p was not consumed. Therefore, it is
112- // safe to reconstruct the box so that it gets deallocated.
108+ return if ret == 0 {
109+ Ok ( Thread { id : native } )
110+ } else {
111+ // The thread failed to start and as a result `data` was not consumed.
112+ // Therefore, it is safe to reconstruct the box so that it gets deallocated.
113113 drop ( Box :: from_raw ( data) ) ;
114114 Err ( io:: Error :: from_raw_os_error ( ret) )
115- } else {
116- Ok ( Thread { id : native } )
117115 } ;
118116
119117 extern "C" fn thread_start ( data : * mut libc:: c_void ) -> * mut libc:: c_void {
0 commit comments