-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unix: RwLock is incorrect #53127
Comments
I based my statements on http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_rwlock_wrlock.html. @sfackler points out that at https://linux.die.net/man/3/pthread_rwlock_wrlock, behavior for re-acquiring the write lock is defined as "may deadlock" -- but not UB. However, we also use this implementation on non-Linux platforms, e.g. macOS. |
macOS does explicitly identify the behavior as undefined. |
FWIW, I think we should stop using the platform-specific implementations, and just roll our own based on thread (un)parking. |
cc @alexcrichton - we talked about this a bit during RustConf. |
I agree that we're basically at the point that there's a ridiculous amount of constraints from OS primitives that the only program which doesn't have undefined behavior is correct ones, and we all know how often we write correct programs. All these discussions are spread out over a number of issues though and PRs, and it's really difficult to keep it all in my own head at least. "This is UB" is a very strong motivation for reimplementing the standard library's primitives, but I think the scale of a change such as this would probably want to go through the RFC process. Such an RFC would be a great location to centralize all the various hazards of OS primitives and how unreasonable it is for us to try to appease all possible implementations. That in turns provides excellent motivation for alternative strategies. |
You mean like this RFC? rust-lang/rfcs#1632 |
Correction: Even some correct programs are UB. Reentrancy on the read lock of an Whether reentrancy that leads to deadlocks is "correct" is open for interpretation, I guess ;) but anyway, it is safe, and hence "correct enough" for UB to be critical. |
I've opened an internals post to continue more long-form discussion on the topic of continuing to fix these issues. |
Use the parking_lot locking primitives This PR adds the [`parking_lot`](https://crates.io/crates/parking_lot) code to libstd and uses it for the `sys_common::{mutex,rwlock,condvar,remutex}` implementations. This has been discussed in https://internals.rust-lang.org/t/standard-library-synchronization-primitives-and-undefined-behavior/8439/9 Thanks @Amanieu for mentoring when doing this, and basically all the code is his as well of course. Fixes #35836 Fixes #53127
Use the parking_lot locking primitives This PR adds the [`parking_lot`](https://crates.io/crates/parking_lot) code to libstd and uses it for the `sys_common::{mutex,rwlock,condvar,remutex}` implementations. This has been discussed in https://internals.rust-lang.org/t/standard-library-synchronization-primitives-and-undefined-behavior/8439/9 Thanks @Amanieu for mentoring when doing this, and basically all the code is his as well of course. Fixes #35836 Fixes #53127
I just noticed that the latest version of the POSIX docs mandate
So some time between the 1997 version and the 2018 version, this seems to have changed. Can we expect Apple (and generally all our POSIX platforms) to follow a recent enough POSIX to rely on this? |
Older versions of glibc (pre-2.25) use hardware lock elision on Intel CPUs which makes recursive locking succeed when it should otherwise deadlock. |
Looks like even the 2004 version already says
"may deadlock" here could be interpreted as "or cause UB", but then saying "may deadlock" would be redundant as of course a deadlock is a valid implementation of UB. So arguably, UB was not permitted any more for 15 years now. @Amanieu Bummer, this means we still need to keep the extra reentrant-rwlock-checks around in libstd (but we should have comments explaining that this is just to defend against non-compliant implementations). |
For the question of whether we can rely on macOS using a recent enough POSIX, I found this "conformance statement" but could not figure out which POSIX version it says macOS conforms with. |
Relevant issue: #33770 |
Oh, that was for Mutex as well, not rust RwLock? This is particularly scary... do they still do that? I would think if |
I believe they still do that, but I haven't checked. |
For For |
Yes, only for For |
Explain our RwLock implementation Turns out that [with the latest POSIX docs](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html), our `RwLock` implementation is actually correct. However, we cannot fully rely on that due to bugs in older glibc (fix released in 2016). Update the comments to explain that. I also clarified our Mutex docs a bit and fixed another instance of rust-lang#55865. r? @Amanieu Fixes rust-lang#53127
Explain our RwLock implementation Turns out that [with the latest POSIX docs](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html), our `RwLock` implementation is actually correct. However, we cannot fully rely on that due to bugs in older glibc (fix released in 2016). Update the comments to explain that. I also clarified our Mutex docs a bit and fixed another instance of rust-lang#55865. r? @Amanieu Fixes rust-lang#53127
Explain our RwLock implementation Turns out that [with the latest POSIX docs](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html), our `RwLock` implementation is actually correct. However, we cannot fully rely on that due to bugs in older glibc (fix released in 2016). Update the comments to explain that. I also clarified our Mutex docs a bit and fixed another instance of rust-lang#55865. r? @Amanieu Fixes rust-lang#53127
Explain our RwLock implementation Turns out that [with the latest POSIX docs](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html), our `RwLock` implementation is actually correct. However, we cannot fully rely on that due to bugs in older glibc (fix released in 2016). Update the comments to explain that. I also clarified our Mutex docs a bit and fixed another instance of rust-lang#55865. r? @Amanieu Fixes rust-lang#53127
I think the
sys::unix::rwlock
implementation is incorrect in the sense that it has undefined behavior, for two reasons:The access toThis is fixed.write_locked
is not properly synchronized: Inread
, we accesswrite_locked
even ifpthread_rwlock_rdlock
failed.write
. If we really want to use POSIX rwlocks, I think we have to implement a reentrancy detector. (And then maybe we also want to use that for mutex, so that we can use the static initializer and the most efficient code path?)The text was updated successfully, but these errors were encountered: