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

Rooting objects #60

Open
CeleritasCelery opened this issue Jan 23, 2024 · 2 comments
Open

Rooting objects #60

CeleritasCelery opened this issue Jan 23, 2024 · 2 comments

Comments

@CeleritasCelery
Copy link

I was reading over the section about dereferencing safely and noticed that there was not any way to root objects. I don't know if this already planned to be covered in the section on garbage collection, but I think it is a really interesting problem that doesn't have a easy solution. It seems like the two approaches used for Rust thus far are either mutation sessions where you can only access heap objects in a closure or having some macro with drop guards. Each have their own trade-offs and I am curious what rust-hosted-langs recommends.

@pliniker
Copy link
Member

In this project we're using mutation sessions. See https://github.com/rust-hosted-langs/book/blob/master/interpreter/src/memory.rs#L142 for the interface and usage. This is essentially just the interior mutability pattern, and thus as a pattern that Rust widely supports, has seemed to me the more likely to be sustainable in a larger codebase.

As for rooting, you're right, I haven't explicitly addressed this yet. I intend to in the WIP section on GC. In short, though, everything referenced by a Thread object should be considered as roots: https://github.com/rust-hosted-langs/book/blob/master/interpreter/src/vm.rs#L178

There are some holes in the safety of the mutation session implementation currently: I think at present you could instantiate two separate VMs each with their own heap, but they do not validate that a Thread and its roots are associated with a particular instance. That's a TODO.

If you see any other gaps/holes I would love to know! Thank you for your interest :)

@CeleritasCelery
Copy link
Author

CeleritasCelery commented Jan 29, 2024

Thank you. Just looking over the code, and had a few questions:

Can roots be stored outside of Memory, or each time you open a mutating session do you need to reaccess your roots? If they are stored outside, how to find them during garbage collection?

With the Mutator trait you can only have a single run method with static input and output types. How would handle a struct that has many methods, like vec or hashmap? Would you have to define you input type as some sort of enum that tells the run method which operation to perform?

Looking at the repl it seems like you would be unable to call GC at all during the execution of a function (which could be arbitrarily long) because the whole thing is evaluated inside a mutation session. Is that the case?

What would prevent me from doing the following?

  1. inside a mutation session clone a CellPtr<T>
  2. change something so that the original T is not accessible (this is not a problem because GC can't run, so it is still safe to access)
  3. pass the cloned CellPtr<T> out of the mutation session via the Output type or Thread-local storage.
  4. run garbage collection (the original T is now collected and freed).
  5. pass the CellPtr<T> back into a mutation session and then convert it to a ScopedPtr via get.
  6. try to access T (triggering UB via UAF)

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

No branches or pull requests

2 participants