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

Add methods to 'leak' RefCell borrows as references with the lifetime of the original reference #68712

Merged
merged 3 commits into from Feb 26, 2020

Conversation

@HeroicKatora
Copy link
Contributor

HeroicKatora commented Jan 31, 2020

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.

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.

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

This comment has been minimized.

Copy link
Collaborator

rust-highfive commented Jan 31, 2020

r? @joshtriplett

(rust_highfive has picked a reviewer for you, use r? to override)

@Dylan-DPC

This comment has been minimized.

Copy link
Member

Dylan-DPC commented Feb 10, 2020

Copy link
Member

dtolnay left a comment

Neat!

@dtolnay

This comment has been minimized.

Copy link
Member

dtolnay commented Feb 11, 2020

Could you please make a tracking issue and add in the issue number?

src/libcore/cell.rs Outdated Show resolved Hide resolved
@Mark-Simulacrum

This comment has been minimized.

Copy link
Member

Mark-Simulacrum commented Feb 11, 2020

Should we add similar functions to MutexGuard and RwLockReadGuard/RwLockWriteGuard?

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.

@ProgrammaticNajel

This comment has been minimized.

Copy link

ProgrammaticNajel commented Feb 21, 2020

Ping from triage. @HeroicKatora any updates on this? Thanks.

src/libcore/cell.rs Outdated Show resolved Hide resolved
src/libcore/cell.rs Outdated Show resolved Hide resolved
@HeroicKatora

This comment has been minimized.

Copy link
Contributor Author

HeroicKatora commented Feb 24, 2020

I've reworded the sections in question. The decision of MutexGuard and forceful deborrow seems like it should be provided in a separate PR.

Copy link
Member

dtolnay left a comment

Looks good! Thanks for including the MutexGuard, RwLockReadGuard/RwLockWriteGuard, and forceful deborrow suggestions in the tracking issue.

@dtolnay

This comment has been minimized.

Copy link
Member

dtolnay commented Feb 24, 2020

@bors r+

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Feb 24, 2020

📌 Commit 329022d has been approved by dtolnay

Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Feb 25, 2020
…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.
bors added a commit that referenced this pull request Feb 25, 2020
Rollup of 8 pull requests

Successful merges:

 - #67637 (Add primitive module to libcore)
 - #68712 (Add methods to 'leak' RefCell borrows as references with the lifetime of the original reference)
 - #69208 (debug_assert a few more raw pointer methods)
 - #69387 (Deduplicate identifier printing a bit)
 - #69423 (syntax: Remove `Nt(Impl,Trait,Foreign)Item`)
 - #69429 (remove redundant clones and import)
 - #69447 (Minor refactoring of statement parsing)
 - #69457 (Clean up e0370 e0371)

Failed merges:

r? @ghost
bors added a commit that referenced this pull request Feb 26, 2020
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.

This comment has been minimized.

Copy link
@RalfJung

RalfJung Feb 26, 2020

Member

"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.)

This comment has been minimized.

Copy link
@HeroicKatora

HeroicKatora Feb 26, 2020

Author Contributor

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.

@bors bors merged commit 86b9377 into rust-lang:master Feb 26, 2020
4 checks passed
4 checks passed
pr Build #20200224.22 succeeded
Details
pr (Linux mingw-check) Linux mingw-check succeeded
Details
pr (Linux x86_64-gnu-llvm-7) Linux x86_64-gnu-llvm-7 succeeded
Details
pr (Linux x86_64-gnu-tools) Linux x86_64-gnu-tools succeeded
Details
Centril added a commit to Centril/rust that referenced this pull request Mar 15, 2020
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

9 participants
You can’t perform that action at this time.