-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Direct Rc/Weak cycle causes double free #12046
Comments
I just ran in to this problem while writing some (slightly more advanced code) https://gist.github.com/Skrylar/8779719 Currently breaks many designs of GUIs. |
I believe that the sequence of events looks like this:
I think that when the destructor for |
Looks like you got it in one:
is the diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs
index 7d0ddb2..79d6d68 100644
--- a/src/libstd/rc.rs
+++ b/src/libstd/rc.rs
@@ -78,8 +78,12 @@ impl<T> Drop for Rc<T> {
fn drop(&mut self) {
+ info!("Rc: dropping {}", self.ptr);
unsafe {
if self.ptr != 0 as *mut RcBox<T> {
+ info!("Rc: strong = {}, weak = {}", (*self.ptr).strong, (*self.ptr).weak);
(*self.ptr).strong -= 1;
if (*self.ptr).strong == 0 {
+ info!("Rc: destroying");
read_ptr(self.borrow()); // destroy the contained object
if (*self.ptr).weak == 0 {
+ info!("Rc: freeing");
exchange_free(self.ptr as *u8)
@@ -155,6 +159,9 @@ impl<T> Drop for Weak<T> {
fn drop(&mut self) {
+ info!("Weak: dropping {}", self.ptr);
unsafe {
if self.ptr != 0 as *mut RcBox<T> {
+ info!("Weak: strong = {}, weak = {}", (*self.ptr).strong, (*self.ptr).weak);
(*self.ptr).weak -= 1;
if (*self.ptr).weak == 0 && (*self.ptr).strong == 0 {
+ info!("Weak: freeing");
exchange_free(self.ptr as *u8) |
I think we can just reorder the decrements. |
One side effect of re-ordering the decrements is that a weak pointer could be upgraded while the last reference to the box is being destroyed, which I think may cause problems because you'd have a strong reference to a thing that has had |
A weak pointer inside itself will have its destructor run when the last strong pointer to that data disappears, so we need to make sure that the Weak and Rc destructors don't duplicate work (i.e. freeing). By making the Rcs effectively take a weak pointer, we ensure that no Weak destructor will free the pointer while still ensuring that Weak pointers can't be upgraded to strong ones as the destructors run. This approach of starting weak at 1 is what libstdc++ does. Fixes #12046.
This commit is a replacement for rust-lang#1417 now that rust-lang/rust#12046 has landed. While I was here I went ahead and updated the Wasmtime used in CI and adapted its command line as well.
This commit is a replacement for #1417 now that rust-lang/rust#12046 has landed. While I was here I went ahead and updated the Wasmtime used in CI and adapted its command line as well.
crashes with a double free when run, with and without optimisations.
I'm investigating.
The text was updated successfully, but these errors were encountered: