Skip to content

Commit 673b3b1

Browse files
authored
Merge pull request #4748 from RalfJung/deadlock-empty-stack
fix empty stack in deadlock error message
2 parents 5339794 + a9e56e4 commit 673b3b1

23 files changed

+101
-102
lines changed

src/tools/miri/src/concurrency/thread.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
834834
// sleep until the first callback.
835835
interp_ok(SchedulingAction::Sleep(sleep_time))
836836
} else {
837-
throw_machine_stop!(TerminationInfo::Deadlock);
837+
throw_machine_stop!(TerminationInfo::GlobalDeadlock);
838838
}
839839
}
840840
}

src/tools/miri/src/diagnostics.rs

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ pub enum TerminationInfo {
3232
history: tree_diagnostics::HistoryData,
3333
},
3434
Int2PtrWithStrictProvenance,
35-
Deadlock,
35+
/// All threads are blocked.
36+
GlobalDeadlock,
37+
/// Some thread discovered a deadlock condition (e.g. in a mutex with reentrancy checking).
38+
LocalDeadlock,
3639
MultipleSymbolDefinitions {
3740
link_name: Symbol,
3841
first: SpanData,
@@ -76,7 +79,8 @@ impl fmt::Display for TerminationInfo {
7679
),
7780
StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
7881
TreeBorrowsUb { title, .. } => write!(f, "{title}"),
79-
Deadlock => write!(f, "the evaluated program deadlocked"),
82+
GlobalDeadlock => write!(f, "the evaluated program deadlocked"),
83+
LocalDeadlock => write!(f, "a thread deadlocked"),
8084
MultipleSymbolDefinitions { link_name, .. } =>
8185
write!(f, "multiple definitions of symbol `{link_name}`"),
8286
SymbolShimClashing { link_name, .. } =>
@@ -245,10 +249,39 @@ pub fn report_result<'tcx>(
245249
Some("unsupported operation"),
246250
StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } =>
247251
Some("Undefined Behavior"),
248-
Deadlock => {
252+
LocalDeadlock => {
249253
labels.push(format!("this thread got stuck here"));
250254
None
251255
}
256+
GlobalDeadlock => {
257+
// Global deadlocks are reported differently: just show all blocked threads.
258+
// The "active" thread might actually be terminated, so we ignore it.
259+
let mut any_pruned = false;
260+
for (thread, stack) in ecx.machine.threads.all_blocked_stacks() {
261+
let stacktrace = Frame::generate_stacktrace_from_stack(stack);
262+
let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
263+
any_pruned |= was_pruned;
264+
report_msg(
265+
DiagLevel::Error,
266+
format!("the evaluated program deadlocked"),
267+
vec![format!(
268+
"thread `{}` got stuck here",
269+
ecx.machine.threads.get_thread_display_name(thread)
270+
)],
271+
vec![],
272+
vec![],
273+
&stacktrace,
274+
Some(thread),
275+
&ecx.machine,
276+
)
277+
}
278+
if any_pruned {
279+
ecx.tcx.dcx().note(
280+
"some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace"
281+
);
282+
}
283+
return None;
284+
}
252285
MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
253286
};
254287
#[rustfmt::skip]
@@ -408,9 +441,7 @@ pub fn report_result<'tcx>(
408441
};
409442

410443
let stacktrace = ecx.generate_stacktrace();
411-
let (stacktrace, mut any_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
412-
413-
let mut show_all_threads = false;
444+
let (stacktrace, pruned) = prune_stacktrace(stacktrace, &ecx.machine);
414445

415446
// We want to dump the allocation if this is `InvalidUninitBytes`.
416447
// Since `format_interp_error` consumes `e`, we compute the outut early.
@@ -425,15 +456,6 @@ pub fn report_result<'tcx>(
425456
.unwrap();
426457
writeln!(extra, "{:?}", ecx.dump_alloc(*alloc_id)).unwrap();
427458
}
428-
MachineStop(info) => {
429-
let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
430-
match info {
431-
TerminationInfo::Deadlock => {
432-
show_all_threads = true;
433-
}
434-
_ => {}
435-
}
436-
}
437459
_ => {}
438460
}
439461

@@ -464,28 +486,8 @@ pub fn report_result<'tcx>(
464486

465487
eprint!("{extra}"); // newlines are already in the string
466488

467-
if show_all_threads {
468-
for (thread, stack) in ecx.machine.threads.all_blocked_stacks() {
469-
if thread != ecx.active_thread() {
470-
let stacktrace = Frame::generate_stacktrace_from_stack(stack);
471-
let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
472-
any_pruned |= was_pruned;
473-
report_msg(
474-
DiagLevel::Error,
475-
format!("the evaluated program deadlocked"),
476-
vec![format!("this thread got stuck here")],
477-
vec![],
478-
vec![],
479-
&stacktrace,
480-
Some(thread),
481-
&ecx.machine,
482-
)
483-
}
484-
}
485-
}
486-
487489
// Include a note like `std` does when we omit frames from a backtrace
488-
if any_pruned {
490+
if pruned {
489491
ecx.tcx.dcx().note(
490492
"some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
491493
);
@@ -574,7 +576,7 @@ pub fn report_msg<'tcx>(
574576
err.span(span);
575577

576578
// Show main message.
577-
if span != DUMMY_SP {
579+
if !span.is_dummy() {
578580
for line in span_msg {
579581
err.span_label(span, line);
580582
}

src/tools/miri/src/shims/unix/sync.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
538538
throw_ub_format!(
539539
"trying to acquire default mutex already locked by the current thread"
540540
),
541-
MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock),
541+
MutexKind::Normal => throw_machine_stop!(TerminationInfo::LocalDeadlock),
542542
MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"),
543543
MutexKind::Recursive => {
544544
this.mutex_lock(&mutex.mutex_ref)?;

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
error: the evaluated program deadlocked
2-
--> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC
3-
|
4-
LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0);
5-
| ^ this thread got stuck here
6-
71
error: the evaluated program deadlocked
82
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
93
|
104
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
11-
| ^ this thread got stuck here
5+
| ^ thread `main` got stuck here
126
|
137
= note: BACKTRACE:
148
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
@@ -23,6 +17,12 @@ LL | | })
2317
LL | | .join()
2418
| |_______________^
2519

20+
error: the evaluated program deadlocked
21+
--> tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC
22+
|
23+
LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0);
24+
| ^ thread `unnamed-ID` got stuck here
25+
2626
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
2727

2828
error: aborting due to 2 previous errors

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ fn main() {
1212
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
1313
// A "normal" mutex properly tries to acquire the lock even if its is already held
1414
// by the current thread -- and then we deadlock.
15-
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: the evaluated program deadlocked
15+
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: a thread deadlocked
1616
}
1717
}

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: the evaluated program deadlocked
1+
error: a thread deadlocked
22
--> tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs:LL:CC
33
|
44
LL | libc::pthread_mutex_lock(&mut mutex as *mut _);

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: the evaluated program deadlocked
22
--> tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC
33
|
44
LL | libc::pthread_rwlock_wrlock(rw.get());
5-
| ^ this thread got stuck here
5+
| ^ thread `main` got stuck here
66

77
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
88

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
error: the evaluated program deadlocked
2-
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
3-
|
4-
LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
5-
| ^ this thread got stuck here
6-
71
error: the evaluated program deadlocked
82
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
93
|
104
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
11-
| ^ this thread got stuck here
5+
| ^ thread `main` got stuck here
126
|
137
= note: BACKTRACE:
148
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
@@ -23,6 +17,12 @@ LL | | })
2317
LL | | .join()
2418
| |_______________^
2519

20+
error: the evaluated program deadlocked
21+
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
22+
|
23+
LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
24+
| ^ thread `unnamed-ID` got stuck here
25+
2626
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
2727

2828
error: aborting due to 2 previous errors

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: the evaluated program deadlocked
22
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC
33
|
44
LL | libc::pthread_rwlock_rdlock(rw.get());
5-
| ^ this thread got stuck here
5+
| ^ thread `main` got stuck here
66

77
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
88

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
error: the evaluated program deadlocked
2-
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
3-
|
4-
LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
5-
| ^ this thread got stuck here
6-
71
error: the evaluated program deadlocked
82
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
93
|
104
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
11-
| ^ this thread got stuck here
5+
| ^ thread `main` got stuck here
126
|
137
= note: BACKTRACE:
148
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
@@ -23,6 +17,12 @@ LL | | })
2317
LL | | .join()
2418
| |_______________^
2519

20+
error: the evaluated program deadlocked
21+
--> tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
22+
|
23+
LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
24+
| ^ thread `unnamed-ID` got stuck here
25+
2626
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
2727

2828
error: aborting due to 2 previous errors

0 commit comments

Comments
 (0)