@@ -1051,7 +1051,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
1051
1051
// See if this thread can do something else.
1052
1052
match this. run_on_stack_empty ( ) ? {
1053
1053
Poll :: Pending => { } // keep going
1054
- Poll :: Ready ( ( ) ) => this. terminate_active_thread ( false ) ?,
1054
+ Poll :: Ready ( ( ) ) =>
1055
+ this. terminate_active_thread ( TerminatedThreadTls :: Deallocate ) ?,
1055
1056
}
1056
1057
}
1057
1058
}
@@ -1066,12 +1067,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
1066
1067
}
1067
1068
1068
1069
/// Handles thread termination of the active thread: wakes up threads joining on this one,
1069
- /// and deallocates thread-local statics (unless `leak_tls` is set, in which case the thread's
1070
- /// TLS are marked as static roots for leakage analysis).
1070
+ /// and deals with the thread's thread-local statics according to `tls`.
1071
1071
///
1072
1072
/// This is called by the eval loop when a thread's on_stack_empty returns `Ready`.
1073
1073
#[ inline]
1074
- fn terminate_active_thread ( & mut self , leak_tls : bool ) -> InterpResult < ' tcx > {
1074
+ fn terminate_active_thread ( & mut self , tls : TerminatedThreadTls ) -> InterpResult < ' tcx > {
1075
1075
let this = self . eval_context_mut ( ) ;
1076
1076
let thread = this. active_thread_mut ( ) ;
1077
1077
assert ! ( thread. stack. is_empty( ) , "only threads with an empty stack can be terminated" ) ;
@@ -1080,20 +1080,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
1080
1080
let current_span = this. machine . current_span ( ) ;
1081
1081
let thread_local_allocations =
1082
1082
this. machine . threads . thread_terminated ( this. machine . data_race . as_mut ( ) , current_span) ;
1083
- if leak_tls {
1084
- // Add thread-local statics to static roots and skip deallocating backing memory
1085
- for ptr in thread_local_allocations {
1086
- if let Some ( alloc) = ptr. provenance . get_alloc_id ( ) {
1087
- trace ! ( "Thread-local static leaked and stored as static root: {:?}" , alloc) ;
1088
- this. machine . static_roots . push ( alloc) ;
1089
- }
1090
- }
1091
- } else {
1092
- // Deallocate backing memory of thread-local statics
1093
- for ptr in thread_local_allocations {
1094
- this. deallocate_ptr ( ptr. into ( ) , None , MiriMemoryKind :: Tls . into ( ) ) ?;
1083
+ for ptr in thread_local_allocations {
1084
+ match tls {
1085
+ TerminatedThreadTls :: Deallocate =>
1086
+ this. deallocate_ptr ( ptr. into ( ) , None , MiriMemoryKind :: Tls . into ( ) ) ?,
1087
+ TerminatedThreadTls :: Leak =>
1088
+ if let Some ( alloc) = ptr. provenance . get_alloc_id ( ) {
1089
+ trace ! ( "Thread-local static leaked and stored as static root: {:?}" , alloc) ;
1090
+ this. machine . static_roots . push ( alloc) ;
1091
+ } ,
1095
1092
}
1096
1093
}
1097
1094
Ok ( ( ) )
1098
1095
}
1099
1096
}
1097
+
1098
+ /// What to do with TLS allocations from terminated threads
1099
+ pub enum TerminatedThreadTls {
1100
+ /// Deallocate backing memory of thread-local statics as usual
1101
+ Deallocate ,
1102
+ /// Skip deallocating backing memory of thread-local statics and consider all memory reachable
1103
+ /// from them as not leaked (like global `static`s).
1104
+ Leak ,
1105
+ }
0 commit comments