-
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
Add methods to 'leak' RefCell borrows as references with the lifetime of the original reference #68712
Conversation
Usually, references to the interior are only created by the `Deref` and `DerefMut` impl of the guards `Ref` and `RefMut`. Note that `RefCell` already has to cope with leaks of such guards which, when it occurs, effectively makes it impossible to ever acquire a mutable guard or any guard for `Ref` and `RefMut` respectively. It is already safe to use this to create a reference to the inner of the ref cell that lives as long as the reference to the `RefCell` itself, e.g. ```rust fn leak(r: &RefCell<usize>) -> Option<&usize> { let guard = r.try_borrow().ok()?; let leaked = Box::leak(Box::new(guard)); Some(&*leaked) } ``` The newly added methods allow the same reference conversion without an indirection over a leaked allocation and composing with both borrow and try_borrow without additional method combinations.
(rust_highfive has picked a reviewer for you, use r? to override) |
r? @dtolnay |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat!
Could you please make a tracking issue and add in the issue number? |
Should we add similar functions to I would also suggest adding forceful "deborrow" functions like parking_lot's https://docs.rs/lock_api/0.3.3/lock_api/struct.Mutex.html#method.force_unlock to accompany this API, but that can be done later, and potentially as a separate feature gate. |
Ping from triage. @HeroicKatora any updates on this? Thanks. |
I've reworded the sections in question. The decision of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Thanks for including the MutexGuard, RwLockReadGuard/RwLockWriteGuard, and forceful deborrow suggestions in the tracking issue.
@bors r+ |
📌 Commit 329022d has been approved by |
…tolnay Add methods to 'leak' RefCell borrows as references with the lifetime of the original reference Usually, references to the interior are only created by the `Deref` and `DerefMut` impl of the guards `Ref` and `RefMut`. Note that `RefCell` already has to cope with leaks of such guards which, when it occurs, effectively makes it impossible to ever acquire a mutable guard or any guard for `Ref` and `RefMut` respectively. It is already safe to use this to create a reference to the inner of the ref cell that lives as long as the reference to the `RefCell` itself, e.g. ```rust fn leak(r: &RefCell<usize>) -> Option<&usize> { let guard = r.try_borrow().ok()?; let leaked = Box::leak(Box::new(guard)); Some(&*leaked) } ``` The newly added methods allow the same reference conversion without an indirection over a leaked allocation. It's placed on the `Ref`/`RefMut` to compose with both borrow and try_borrow directly.
Rollup of 5 pull requests Successful merges: - #68712 (Add methods to 'leak' RefCell borrows as references with the lifetime of the original reference) - #69209 (Miscellaneous cleanup to formatting) - #69381 (Allow getting `no_std` from the config file) - #69434 (rustc_metadata: Use binary search from standard library) - #69447 (Minor refactoring of statement parsing) Failed merges: r? @ghost
#[unstable(feature = "cell_leak", issue = "69099")] | ||
pub fn leak(orig: Ref<'b, T>) -> &'b T { | ||
// By forgetting this Ref we ensure that the borrow counter in the RefCell never goes back | ||
// to UNUSED again. No further mutable references can be created from the original cell. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"No further mutable references" is not entirely correct -- there is get_mut
which circumvents the borrow counter. (If we felt fancy, we could even make it reset the borrow counter.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment would be more accurate if it were along the lines of 'no further RefMut
can be created'. That said, having a reset_borrows(&mut self)
would work as well and then the comment would become outdated. Since the method seems so natural, I'll try to come up with a PR in the next days and fix this comment then.
…tolnay Add undo_leak to reset RefCell borrow state This method is complementary for the feature cell_leak added in an earlier PR. It allows *safely* reverting the effects of leaking a borrow guard by statically proving that such a guard could not longer exist. This was not added to the existing `get_mut` out of concern of impacting the complexity of the otherwise pure pointer cast and because the name `get_mut` poorly communicates the intent of resetting remaining borrows. This is a follow-up to rust-lang#68712 and uses the same tracking issue, rust-lang#69099, as these methods deal with the same mechanism and the idea came up [in a review comment](rust-lang#68712 (comment)). @dtolnay who reviewed the prior PR. cc @RalfJung
Usually, references to the interior are only created by the
Deref
andDerefMut
impl of the guardsRef
andRefMut
. Note thatRefCell
already has to cope with leaks of such guards which, when it occurs,
effectively makes it impossible to ever acquire a mutable guard or any
guard for
Ref
andRefMut
respectively. It is already safe to usethis to create a reference to the inner of the ref cell that lives as
long as the reference to the
RefCell
itself, e.g.The newly added methods allow the same reference conversion without an
indirection over a leaked allocation. It's placed on the
Ref
/RefMut
tocompose with both borrow and try_borrow directly.