Skip to content

Commit eb97047

Browse files
committed
Auto merge of rust-lang#3943 - RalfJung:pthread-mutex-reentrant, r=RalfJung
pthread mutex: better error in reentrant-locking-UB Also test reentrant locking of PTHREAD_MUTEX_INITIALIZER
2 parents f7400c3 + 1553805 commit eb97047

9 files changed

+51
-15
lines changed

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
483483
// Trying to acquire the same mutex again.
484484
match kind {
485485
MutexKind::Default =>
486-
throw_ub_format!("trying to acquire already locked default mutex"),
486+
throw_ub_format!(
487+
"trying to acquire default mutex already locked by the current thread"
488+
),
487489
MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock),
488490
MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"),
489491
MutexKind::Recursive => {
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//@ignore-target: windows # No pthreads on Windows
22
//
3-
// Check that if we pass NULL attribute, then we get the default mutex type.
3+
// Check that if we pass NULL attribute, then reentrant locking is UB.
44

55
fn main() {
66
unsafe {
77
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
88
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null() as *const _), 0);
99
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
10-
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex
10+
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread
1111
}
1212
}

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr renamed to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
error: Undefined Behavior: trying to acquire already locked default mutex
2-
--> tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC
1+
error: Undefined Behavior: trying to acquire default mutex already locked by the current thread
2+
--> tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs:LL:CC
33
|
44
LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
99
= note: BACKTRACE:
10-
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC
10+
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs:LL:CC
1111

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

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
//@ignore-target: windows # No pthreads on Windows
22
//
3-
// Check that if we do not set the mutex type, it is the default.
3+
// Check that if we do not set the mutex type, it is UB to do reentrant locking. glibc apparently
4+
// actually exploits this, see
5+
// <https://github.molgen.mpg.de/git-mirror/glibc/blob/master/nptl/pthread_mutexattr_settype.c#L31>:
6+
// one must actively call pthread_mutexattr_settype to disable lock elision. This means a call to
7+
// pthread_mutexattr_settype(PTHREAD_MUTEX_NORMAL) makes a difference even if
8+
// PTHREAD_MUTEX_NORMAL == PTHREAD_MUTEX_DEFAULT!
49

510
fn main() {
611
unsafe {
@@ -9,6 +14,6 @@ fn main() {
914
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
1015
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
1116
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
12-
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex
17+
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread
1318
}
1419
}

src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr renamed to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
error: Undefined Behavior: trying to acquire already locked default mutex
2-
--> tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC
1+
error: Undefined Behavior: trying to acquire default mutex already locked by the current thread
2+
--> tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs:LL:CC
33
|
44
LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
99
= note: BACKTRACE:
10-
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC
10+
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs:LL:CC
1111

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

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

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ fn main() {
1010
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
1111
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
1212
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
13+
// A "normal" mutex properly tries to acquire the lock even if its is already held
14+
// by the current thread -- and then we deadlock.
1315
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: deadlock: the evaluated program deadlocked
1416
}
1517
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error: deadlock: the evaluated program deadlocked
2-
--> tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC
2+
--> tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs:LL:CC
33
|
44
LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked
66
|
77
= note: BACKTRACE:
8-
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC
8+
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs:LL:CC
99

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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ignore-target: windows # No pthreads on Windows
2+
//
3+
// Check that if we use PTHREAD_MUTEX_INITIALIZER, then reentrant locking is UB.
4+
// glibc apparently actually exploits this so we better catch it!
5+
6+
fn main() {
7+
unsafe {
8+
let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
9+
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
10+
libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: trying to acquire default mutex already locked by the current thread
2+
--> tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs:LL:CC
3+
|
4+
LL | libc::pthread_mutex_lock(&mut mutex as *mut _);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to 1 previous error
15+

0 commit comments

Comments
 (0)