Skip to content

Commit e17ff2d

Browse files
committed
fix diagnostics printing when triggered during TLS dtor scheduling
1 parent c966a68 commit e17ff2d

File tree

3 files changed

+23
-8
lines changed

3 files changed

+23
-8
lines changed

src/diagnostics.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,15 @@ fn report_msg<'tcx>(
162162
} else {
163163
tcx.sess.diagnostic().span_note_diag(span, title)
164164
};
165-
err.span_label(span, span_msg);
165+
// Show main message.
166+
if span != DUMMY_SP {
167+
err.span_label(span, span_msg);
168+
} else {
169+
// Make sure we show the message even when it is a dummy span.
170+
err.note(&span_msg);
171+
err.note("(no span available)");
172+
}
173+
// Show help messages.
166174
if !helps.is_empty() {
167175
// Add visual separator before backtrace.
168176
helps.last_mut().unwrap().push_str("\n");
@@ -198,7 +206,7 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) {
198206
/// after a step was taken.
199207
pub struct TopFrameInfo<'tcx> {
200208
stack_size: usize,
201-
instance: ty::Instance<'tcx>,
209+
instance: Option<ty::Instance<'tcx>>,
202210
span: Span,
203211
}
204212

@@ -209,11 +217,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
209217
DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty()));
210218

211219
let this = self.eval_context_ref();
220+
if this.active_thread_stack().is_empty() {
221+
// Diagnostics can happen even with the emoty stack (e.g. deallocation thread-local statics).
222+
return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP };
223+
}
212224
let frame = this.frame();
213225

214226
TopFrameInfo {
215227
stack_size: this.active_thread_stack().len(),
216-
instance: frame.instance,
228+
instance: Some(frame.instance),
217229
span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span),
218230
}
219231
}
@@ -237,15 +249,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
237249
if stacktrace.len() < info.stack_size {
238250
assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once");
239251
let frame_info = FrameInfo {
240-
instance: info.instance,
252+
instance: info.instance.unwrap(),
241253
span: info.span,
242254
lint_root: None,
243255
};
244256
stacktrace.insert(0, frame_info);
245-
} else {
257+
} else if let Some(instance) = info.instance {
246258
// Adjust topmost frame.
247259
stacktrace[0].span = info.span;
248-
assert_eq!(stacktrace[0].instance, info.instance, "we should not pop and push a frame in one step");
260+
assert_eq!(stacktrace[0].instance, instance, "we should not pop and push a frame in one step");
249261
}
250262

251263
// Show diagnostics.

src/eval.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,10 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
210210
let res: InterpResult<'_, i64> = (|| {
211211
// Main loop.
212212
loop {
213+
let info = ecx.preprocess_diagnostics();
213214
match ecx.schedule()? {
214215
SchedulingAction::ExecuteStep => {
215-
let info = ecx.preprocess_diagnostics();
216216
assert!(ecx.step()?, "a terminated thread was scheduled for execution");
217-
ecx.process_diagnostics(info);
218217
}
219218
SchedulingAction::ExecuteTimeoutCallback => {
220219
assert!(ecx.machine.communicate,
@@ -232,6 +231,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
232231
break;
233232
}
234233
}
234+
ecx.process_diagnostics(info);
235235
}
236236
let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
237237
Ok(return_code)

src/shims/tls.rs

+3
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
348348
return Ok(())
349349
}
350350
}
351+
// The remaining dtors make some progress each time around the scheduler loop,
352+
// until they return `false` to indicate that they are done.
353+
351354
// The macOS thread wide destructor runs "before any TLS slots get
352355
// freed", so do that first.
353356
if this.schedule_macos_tls_dtor()? {

0 commit comments

Comments
 (0)