-
Notifications
You must be signed in to change notification settings - Fork 19
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 Rc::borrow_mut(&mut Self) #112
Comments
The documentation of
But with this change, it could also return None while the value hasn't been dropped yet, but is just borrowed out mutably through
Using that pattern, everything that only needs immutable access then needs to use a I agree that using a
Note that your implementation breaks and can result in a use-after-free when leaking a RefMut: use std::rc::Rc;
use rc_borrow_mut::RcBorrowMut;
fn main() {
let mut rc = Rc::new("asdf".to_string());
std::mem::forget(Rc::borrow_mut(&mut rc));
drop(rc.clone());
println!("use after free: {rc:?}");
}
|
Minor correction:
Thanks for pointing this out! That's not ideal.
Thanks for pointing this out! 😨 While I knew not to trust destructors, I was under the (false) impression that code like this wouldn't compile: let mut vec = vec![1, 2, 3];
std::mem::forget(vec.iter_mut());
println!("{vec:?}"); Fixing this would require taking ownership of the |
Proposal
Problem statement
It is impossible to get a mutable reference into an
Rc<T>
when the weak reference count is non-zero, even when the strong reference count is 1.Motivation, use-cases
Right now, if I want to share and mutate data in my single-threaded Yew/Webassembly application, I have to use
Rc<RefCell<T>>
. Unfortunately, theRefCell
means that all immutable borrows require aRef
guard. As I originally designed my application around simplyClone
ing the state to share it, my hundreds of immutable accesses are via de-referencing and would all need to be adapted to use aRef
guard.If this proposal is implemented, a guard is only required during mutation. Immutable accesses can take place both by de-referencing (e.g. the synchronous business logic part of my app) and, in the same program, sharing
Weak<T>
's that get upgraded toRc<T>
before the access takes place (e.g. the asynchronous Yew component hierarchy part of my app).Solution sketches
Add
std::rc::RefMut
.Then, either:
Rc<T>::borrow_mut(&mut Self) -> Option<std::rc::RefMut<'_, T>>
(consistent withRc::get_mut
returning anOption
)Rc<T>::borrow_mut(&mut Self) -> std::rc::RefMut<'_, T>
andRc<T>::try_borrow_mut(&mut Self) -> Option<std::rc::RefMut<'_, T>>
(consistent withRefCell::borrow_mut
andRefCell::try_borrow_mut
)The above APIs can be implemented by:
&mut Self
so that it can't becloned
during the processRc
's, so panic or returnNone
.Weak
's cannot upgrade)impl Deref<Target = T> + DerefMut
impl Drop
to restore the strong reference count to 1Links and related work
I implemented this here. It uses unsafe and relies on unspecified implementation details of
Rc
(meaning it would benefit from inclusion instd
), but passes tests under Miri and works in my application.What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.
The text was updated successfully, but these errors were encountered: