-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Tracking Issue for rwlock_try_upgrade
#138559
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
Comments
The original author hasn't had a chance to work on this, so it is open if anybody wants to pick it up. Labeled hard because the queue implementation is pretty tricky. Cc @connortsui20 in case you're interested in working on this since you handled |
I can pick this up (but only after next week because I need to graduate). I have a good idea of what needs to be done given the discussion in rust-lang/libs-team#514, but I will point out that I have no idea how to add rust-lang/libs-team#514 (comment) nor how to support a clippy lint that tells people not to put |
Certainly no rush, congrats! 🎉 Don't worry about Clippy, that wouldn't block anything here. Miri likely wouldn't either but it might not be that bad, @RalfJung may have some ideas about what to do here (rust-lang/libs-team#514 (comment) for context Ralf). |
Also see: rust-lang/libs-team#514 (comment) |
rwlock-try-upgrade
rwlock_try_upgrade
I got bored so I decided to look into this anyways... and now I see the problem that the previous attempt by @ShrigmaDev ran into. TLDR; the layout of Basically, the issue is how to convert a pub struct RwLock<T: ?Sized> {
inner: sys::RwLock,
poison: poison::Flag,
data: UnsafeCell<T>,
}
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
// NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
// `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
// `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
// is preferable over `const* T` to allow for niche optimization.
data: NonNull<T>,
inner_lock: &'a sys::RwLock,
}
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
poison: poison::Guard,
} Observe that the write guard needs a reference back to the original I'm tried to think of ways we could reconstruct this safely, and the only possible method of doing this would be to somehow derive the pointer for the original There is luckily another option, which is what I'll try to implement. We can make it so that the pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
data: NonNull<T>,
inner_lock: &'a sys::RwLock,
poison_flag: &'a poison::Flag,
poison: poison::Guard,
_variance: PhantomData<&'rwlock mut T>,
} In this case, it is trivial to convert between the read and write guards (same fields). I still need to refresh on the semantics of |
I don't think use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
fn try_upgrade<'a, T: ?Sized>(orig: RwLockReadGuard<'a, T>) -> Result<RwLockWriteGuard<'a, T>, RwLockReadGuard<'a, T>> {
todo!() // I don't think this function can soundly return a `RwLockWriteGuard` to the inner data with this signature
}
fn main() {
let rwl: RwLock<&'static str> = RwLock::new("hello, world");
let s: String = String::from("dynamically allocated");
let rg = rwl.read().unwrap();
let mut wg = try_upgrade(rg).unwrap();
*wg = &s;
dbg!(&wg); // "dynamically allocated"
drop(wg);
drop(s);
let wg = rwl.write().unwrap();
dbg!(&wg); // use-after-free
} This code compiles on stable, so IIUC if this If we had a separate Note that all of |
I've skimmed the referenced context but it is not clear to me what the problem with Miri is. The macos rwlock has a subtle provenance bug, is that the issue? Those tests should only be disabled for Miri on macos.
|
I think that was a concern from before, it seems like there is a bigger problem now where it might be impossible to implement this method soundly |
If Miri complains about an actual soundness problem, then the issue is not with Miri. ;) I'm afraid I don't currently have the time to dig into the soundness issue and propose a solution. |
Feature gate:
#![feature(rwlock_try_upgrade)]
This is a tracking issue
RwLock::try_upgrade
, which turns a read guard into a write guard if it is the only lock accessor.Public API
Steps / History
(Remember to update the
S-tracking-*
label when checking boxes.)Rwlock
try_upgrade
method libs-team#514try_upgrade
in a loop (not blocking)Unresolved Questions
Footnotes
https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html ↩
The text was updated successfully, but these errors were encountered: