@@ -33,6 +33,15 @@ enum SchedulingAction {
3333 Sleep ( Duration ) ,
3434}
3535
36+ /// What to do with TLS allocations from terminated threads
37+ pub enum TlsAllocAction {
38+ /// Deallocate backing memory of thread-local statics as usual
39+ Deallocate ,
40+ /// Skip deallocating backing memory of thread-local statics and consider all memory reachable
41+ /// from them as "allowed to leak" (like global `static`s).
42+ Leak ,
43+ }
44+
3645/// Trait for callbacks that can be executed when some event happens, such as after a timeout.
3746pub trait MachineCallback < ' mir , ' tcx > : VisitTags {
3847 fn call ( & self , ecx : & mut InterpCx < ' mir , ' tcx , MiriMachine < ' mir , ' tcx > > ) -> InterpResult < ' tcx > ;
@@ -1051,7 +1060,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10511060 // See if this thread can do something else.
10521061 match this. run_on_stack_empty ( ) ? {
10531062 Poll :: Pending => { } // keep going
1054- Poll :: Ready ( ( ) ) => this. terminate_active_thread ( ) ?,
1063+ Poll :: Ready ( ( ) ) =>
1064+ this. terminate_active_thread ( TlsAllocAction :: Deallocate ) ?,
10551065 }
10561066 }
10571067 }
@@ -1066,21 +1076,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10661076 }
10671077
10681078 /// Handles thread termination of the active thread: wakes up threads joining on this one,
1069- /// and deallocated thread-local statics.
1079+ /// and deals with the thread's thread -local statics according to `tls_alloc_action` .
10701080 ///
10711081 /// This is called by the eval loop when a thread's on_stack_empty returns `Ready`.
10721082 #[ inline]
1073- fn terminate_active_thread ( & mut self ) -> InterpResult < ' tcx > {
1083+ fn terminate_active_thread ( & mut self , tls_alloc_action : TlsAllocAction ) -> InterpResult < ' tcx > {
10741084 let this = self . eval_context_mut ( ) ;
10751085 let thread = this. active_thread_mut ( ) ;
10761086 assert ! ( thread. stack. is_empty( ) , "only threads with an empty stack can be terminated" ) ;
10771087 thread. state = ThreadState :: Terminated ;
10781088
10791089 let current_span = this. machine . current_span ( ) ;
1080- for ptr in
1081- this. machine . threads . thread_terminated ( this. machine . data_race . as_mut ( ) , current_span)
1082- {
1083- this. deallocate_ptr ( ptr. into ( ) , None , MiriMemoryKind :: Tls . into ( ) ) ?;
1090+ let thread_local_allocations =
1091+ this. machine . threads . thread_terminated ( this. machine . data_race . as_mut ( ) , current_span) ;
1092+ for ptr in thread_local_allocations {
1093+ match tls_alloc_action {
1094+ TlsAllocAction :: Deallocate =>
1095+ this. deallocate_ptr ( ptr. into ( ) , None , MiriMemoryKind :: Tls . into ( ) ) ?,
1096+ TlsAllocAction :: Leak =>
1097+ if let Some ( alloc) = ptr. provenance . get_alloc_id ( ) {
1098+ trace ! ( "Thread-local static leaked and stored as static root: {:?}" , alloc) ;
1099+ this. machine . static_roots . push ( alloc) ;
1100+ } ,
1101+ }
10841102 }
10851103 Ok ( ( ) )
10861104 }
0 commit comments