Skip to content
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

rwlock: avoid Stacked Borrows violation #121630

Closed
wants to merge 1 commit into from

Conversation

RalfJung
Copy link
Member

Fixes #121626. Changes code recently added in #110211.

It seems like RwLock assumes that code like this is legal:

use std::cell::UnsafeCell;

fn main() {
    let mut c = UnsafeCell::new(42);
    let ptr = c.get();
    c = UnsafeCell::new(13);
    unsafe { ptr.read(); }
}

However, Stacked Borrows makes this illegal. That may be overeager, and indeed Tree Borrows allows this code, but Tree Borrows might also allow too much code, so until we are more sure about the future of the Rust aliasing model we should avoid code like this.

For the RwLock, this means not mixing direct write access to the mutable local variable node, with access through (interior mutable) shared references.

r? @m-ou-se @joboet

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Feb 26, 2024
node.next.0 = AtomicPtr::new(state.mask(MASK).cast());
node.prev = AtomicLink::new(None);
let mut next = ptr::from_ref(&node)
// These writes can't race.
Copy link
Member Author

@RalfJung RalfJung Feb 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not actually sure why we know that they can't race. After all, as the Miri error shows, an alias can clearly still exist and be used again in the future when these writes happen. This assumption is not new; we've been using non-atomic writes here already before this PR. Previously this was safe code only because rustc did not realize that the NonNull::from(&node) creates a borrow that could last into the next loop iteration.

// Fall back to creating an unnamed `Thread` handle to allow locking in
// TLS destructors.
self.thread
.get_or_init(|| thread_info::current_thread().unwrap_or_else(|| Thread::new(None)));
self.completed = AtomicBool::new(false);
unsafe { self.completed.as_ptr().write(false) }; // can't have a race here
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should probably either make this a relaxed store, or make the function unsafe.

@joboet
Copy link
Contributor

joboet commented Feb 26, 2024

The weird thing is that the code actually doesn't make the assumption you mention; the shared reference that supposedly is invalidated is only created after all mutable accesses have occurred. Or so I thought...

@RalfJung
Copy link
Member Author

It seems Miri found an interleaving where an old shared reference gets used after the next loop iteration did some mutable accesses to the same node again.

If that is itself a bug then this PR is the wrong fix. In that case the SB error in Miri would just mask a data race error.

@joboet
Copy link
Contributor

joboet commented Feb 26, 2024

That is in itself a bug, yes, because the loop is only repeated when the node is not in a queue, otherwise you could get use-after-frees and things like that.

@rust-lang rust-lang deleted a comment from bors Feb 29, 2024
@m-ou-se
Copy link
Member

m-ou-se commented Feb 29, 2024

r? @joboet

@rustbot rustbot assigned joboet and unassigned m-ou-se Feb 29, 2024
@RalfJung RalfJung marked this pull request as draft February 29, 2024 21:06
@RalfJung
Copy link
Member Author

RalfJung commented Mar 2, 2024

This is the wrong fix, we need to figure out where the problem lies in the concurrency logic.

@RalfJung RalfJung closed this Mar 2, 2024
@RalfJung RalfJung deleted the rwlock-sb branch March 2, 2024 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Stacked Borrows violation in macOS RwLock
4 participants