What if there was an option to have a garbage collector for unsafe Rust code?

Early versions of Rust used a garbage collector and it was removed which makes sense because true safety can't really be achieved with tracing but true safety can't be achieved with unsafe Rust code either and having a garbage collector for safety is better than nothing so I was thinking: What if there was an option to have a garbage collector that only targets unsafe code?

You can do garbage collection with the reference-counting types, std::rc::Rc and std::sync::Arc.

I don't get the idea.

In unsafe code, that is exactly the place where one does not want a garbage collector. One want's control over actual bytes of actual memory.


I'm talking about tracing, like let's say you have an unsafe block of code or an unsafe line, what if we could put #[enable(tracing)] over it to enable a tracing gc?

https://en.m.wikipedia.org/wiki/Tracing_garbage_collection I'm talking about tracing not reference counting, and a tracing gc wouldn't really limit you since it's fully automatic and would be smart enough to know what should be collected and what shouldn't.

EDIT: I'm thinking of it like this: Tracing could be used on unsafe code without limiting the unsafe code it would be a great addition to have.

I know, it's not what you are looking for. I proposed reference-counting because it's already available, doesn't require support from the language or compiler, and is doubly useable in unsafe and safe code.

In fact, there are a handful of GC crates that you can start using today, if you don't feel like rolling your own:

I do not have any direct experience with any of these, so please do not consider this an endorsement.


I know 3rd parties have implimented this but I believe having it in the standard library with support from the Rust team would be a better option because it could see wider adoption for when people write unsafe code.

Since std was mentioned, I'm going to directly link to an excellent observation regarding "what belongs in std":

1 Like

That's what the D language is for.

Rust is explicitly about not having GC anywhere, so you don't have the problem of ecosystem split into GC-tainted and GC-clean halves.

tricky unsafe operations (because we trust std verification more than 3rd party crate verification, though even that could potentially change in the future)

A tracing garbage collector to make unsafe code safer without limiting the unsafe code definitely matches this and supports why it should be in the standard library.

My proposal would be having a tracing garbage collector be implimented with something like #[enable(tracing)] and I don't think it would split the community at all. The code written would be able to run with or without the tracing garbage collector so there could also be a flag like #![forbid(tracing)] which'll just ignore the enable flags at compile time so you can use libraries that use tracing as a safety measure can be used without tracing.

I'm confused.

If that is the case why would one want the overheads of a garbage collector?

@ZiCog A tracing garbage collector looks for leaked memory and cleans it up to make it safer so having that as an option to use on your unsafe code could be a good idea because it would be able to make unsafe safer without limiting unsafe and my idea on how it'd be implimented would make sure it wouldn't be forced upon anybody so the community wouldn't be divided.

Except the only time I can see that I want to use 'unsafe' code is when interfacing to some other language, where no garbage collector can go, or when interfacing to hardware devices, where no garbage collector can go.

So, where would this tracing garbage collector be useful ?

For starters the unsafe Rust could that interfaces with other languages can still be traced to an extent and https://reddit.com/r/rust/comments/9wxwi1/_/e9o3tts/?context=1 like this person said it could also be used to make specialized abstractions


and there could be some cases where these might be necessary for your code.

Perhaps, maybe.

How am I going to get that to work on my STM32 F4 micro-controller?

Or my RISC V core in FPGA?

I don't believe what you are asking for can be done with no run-time system in place.

That requirement would change the whole language into something I am not interested in using any more.

Your right it can't be done at compile time, a tracing garbage collector needs to be at runtime and it definitely won't be able to run in some situations, that's why you'd be able to use #![forbid(tracing)] for those situations. In the majority of situations where unsafe is needed a tracing garbage collector would be able to be used there.

Let's put it into perspective like this:

The majority of Rust code people write is safe so a small amount of people would need unsafe. In the cases where unsafe is needed a tracing garbage collector would be useful and only a small amount of unsafe wouldn't be able to use a tracing garbage collector. So only a minority of a minority wouldn't be able to use the tracing garbage collector while the rest of that minority would be able to which would make their code much more safer and even though the majority of people who use Rust don't use unsafe they may indirectly use unsafe through a crate because that's their only option, a great example of that is using a crate to parse JSON. All crates out use unsafe for it and there's no implimentation in the standard library for JSON parsing so that's a situation where someone would be forced to use unsafe indirectly and a situation where a tracing garbage collector could be very helpful. Another example is supporting colored terminal text for windows, there's no safe implimentation for it. Another is using SQLlite with Rust... Again, there's no safe implimentation of this. These are all situations where a garbage collector would be perfect and these are situations many people face (I personally have faced all 3 of these situations).

So if you're going for always-optional garbage collection, that's only used to catch some additional memory unsafety, this sounds more like Valgrind or LLVM sanitizers. Rust supports these, and also has some UB detection in miri.

Would those be able to be seamlessly enabled and disabled though? What if a library I use used those and I wanted to disable it? How would I disable it? Is it as simple as using a flag or is it more complex? And how easy and seamless would enabling these options be? Is it also as simple as a flag or is it more complex? And these things still aren't in the standard library so it would be unlikely for it to be highly adopted. Ontop of that always optional tracing garbage collection perfectly fits the description on what should be in the standard library but it isn't so I'm still convinced that having always optional tracing garbage collection in the standard library would be a huge game changer for Rust because it would make unsafe code safer with an easy way to do so and given the fact Rust is a language that revolves around safety this would be a perfect fit for the language.

Well, what do people use unsafe for ?

  • Performance: Using a GC is counterproductive here.
  • FFI interfaces: Using a GC is impossible here.
  • Low-level data hackery that can result in violations of type-safety or unaligned memory accesses: Using a GC won't help here.
  • Low-level code hackery that can result in violations of thread safety or execution of illegal CPU instructions: Using a GC won't help here.

I have a hard time convincing myself of your claim that a GC would help in most usage scenarios of unsafe code. Memory safety is only a part of Rust's safety contract, and many of the scenarios that require raw pointers can't use a GC for performance or FFI reasons...