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

impl Trace for Rc<T> is not correct #134

Closed
lalaithion opened this issue May 4, 2021 · 7 comments · Fixed by #153
Closed

impl Trace for Rc<T> is not correct #134

lalaithion opened this issue May 4, 2021 · 7 comments · Fixed by #153

Comments

@lalaithion
Copy link
Contributor

The only unsafe code in my application is

use rpds::HashTrieMap;

pub struct Scope<V: Trace + 'static> {
    inner: HashTrieMap<String, Gc<V>>,
}

unsafe impl<V: Trace> Trace for Scope<V> {
    custom_trace!(this, {
        for (_, v) in this.inner.iter() {
            mark(v);
        }
    });
}

(This is essentially a workaround for rpds not implementing Trace).

I've checked, and nothing in the rpds library implements Drop, so I don't see how I'm violating the Trace contract. Is this a bug, or am I missing some invariant I need to maintain?

@andersk
Copy link
Collaborator

andersk commented May 4, 2021

What version are you using? lib.rs line 126 is only a panic in v0.3.x, and your issue sounds like it could be the same as #117 which was fixed in v0.4.0.

@lalaithion
Copy link
Contributor Author

#136

@lalaithion
Copy link
Contributor Author

Hmm, sorry for the preemptive closure. I still get the error when updated to 0.4

@lalaithion lalaithion reopened this May 4, 2021
@lalaithion
Copy link
Contributor Author

Now it's failing on lib.rs:125:9

Trying to run the same code paths via manually calling my binary (vs. in a test) causes "Can't double-unroot a Gc" in lib.rs:226.

@andersk
Copy link
Collaborator

andersk commented May 4, 2021

Are you using #[unsafe_ignore_trace] on a field that contains a Gc? That’s known to be a possible cause of that panic. (Well, known to me as of 15 minutes ago, at least. I assume it’s been known to the original authors for longer. 🙂 The README does warn “Incorrect usage of unsafe_empty_trace and unsafe_ignore_trace may lead to unsafety.”)

If not, you’ve probably found a new bug, and we’ll need to see some code that reproduces it to investigate further.

@lalaithion
Copy link
Contributor Author

Took me a couple tries to figure out exactly where the issue was coming from, but here's my reproduction:

https://gist.github.com/lalaithion/125704f8f69408ec6d825b9075804787

@andersk
Copy link
Collaborator

andersk commented May 24, 2021

Hmm. I was going to suggest that your Trace implementation might be wrong because rpds::HashTrieMap uses structural sharing of trie branches between instances. However, if that’s a bug, then our Trace implementation for Rc is wrong too, and, well…

use gc::Gc;
use std::rc::Rc;

fn main() {
    let r = Rc::new(Gc::new(()));
    Gc::new((Rc::clone(&r), r));
}
thread 'main' panicked at 'Can't double-unroot a Gc<T>', /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/gc-0.4.1/src/lib.rs:226:9
stack backtrace:
   0: std::panicking::begin_panic
             at /rustc/5dc8789e300930751a78996da0fa906be5a344a2/library/std/src/panicking.rs:541:12
   1: <gc::Gc<T> as gc::trace::Trace>::unroot
             at /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/gc-0.4.1/src/lib.rs:226:9
   2: <alloc::rc::Rc<T> as gc::trace::Trace>::unroot::mark
             at /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/gc-0.4.1/src/trace.rs:85:17
   3: <alloc::rc::Rc<T> as gc::trace::Trace>::unroot
             at /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/gc-0.4.1/src/trace.rs:241:9
   4: <(A,B) as gc::trace::Trace>::unroot::mark
             at /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/gc-0.4.1/src/trace.rs:85:17
   5: <(A,B) as gc::trace::Trace>::unroot::avoid_lints
             at /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/gc-0.4.1/src/trace.rs:205:32
   6: <(A,B) as gc::trace::Trace>::unroot
             at /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/gc-0.4.1/src/trace.rs:222:1
   7: gc::Gc<T>::new
             at /home/anders/.cargo/registry/src/github.com-1ecc6299db9ec823/gc-0.4.1/src/lib.rs:76:13
   8: test::main
             at ./test.rs:6:5
   9: core::ops::function::FnOnce::call_once
             at /rustc/5dc8789e300930751a78996da0fa906be5a344a2/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

😕

@lalaithion lalaithion changed the title assert in lib.rs:126 panics impl Trace for Rc<T> is not correct May 25, 2021
CertainLach added a commit to CertainLach/jrsonnet-gc that referenced this issue Jul 4, 2021
As it is incorrect and can be a footgun
Manishearth/rust-gc#134

Signed-off-by: Yaroslav Bolyukin <iam@lach.pw>
andersk added a commit to andersk/rust-gc that referenced this issue Dec 19, 2022
I’m not sure if these instances would work with a better tracing
algorithm, but they do not work correctly with this one.

    let r = Rc::new(Gc::new(()));
    Gc::new((Rc::clone(&r), r));
    // → thread 'main' panicked at 'Can't double-unroot a Gc<T>'

Fixes Manishearth#134.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
andersk added a commit to andersk/rust-gc that referenced this issue Dec 19, 2022
I’m not sure if these instances would work with a better tracing
algorithm, but they do not work correctly with this one.

    let r = Rc::new(Gc::new(()));
    Gc::new((Rc::clone(&r), r));
    // → thread 'main' panicked at 'Can't double-unroot a Gc<T>'

Fixes Manishearth#134.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
andersk added a commit to andersk/rust-gc that referenced this issue Dec 19, 2022
I’m not sure if these impls would work with a better tracing
algorithm, but they do not work correctly with this one.

    let r = Rc::new(Gc::new(()));
    Gc::new((Rc::clone(&r), r));
    // → thread 'main' panicked at 'Can't double-unroot a Gc<T>'

Fixes Manishearth#134.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants