-
Notifications
You must be signed in to change notification settings - Fork 309
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
Rust doesn't guarantee memory safety with GC #1532
Comments
I think this issue is fundamental, and at this point makes Rust unsuitable for implementing a garbage-collected language like Emacs Lisp. In particular, I think it's going to turn out to be impossible to switch to a moving collector for remacs, even though it's quite possible with GNU Emacs. Garbage collection fundamentally collides with the "single owner" concept of Rust, as far as I can tell. Rust is likely to optimize code, at some point in the future, by exploiting the fact that only one writable reference to a data item exists; and the garbage collector, which operates without interaction with Rust, violates that assumption. My personal conclusion is that Rust and Emacs just don't play well together, right now. I think proper garbage collection is going to require Rust compiler support (ideally, DWARF information that makes it possible to tell which stack and heap locations hold Lisp Objects). Anyway, that's just one opinion, and it's quite true that with the current rust toolchain, and the current mark-and-sweep collector, the problems that potentially might occur actually don't. So I would suggest that we find a solution that works for moving collectors, too (and incidentally we might be able to use the SpiderMonkey collector directly), even if that requires work on the Rust compiler as well as remacs. |
I am not quite as concerned at the long term viability yet. Our issues today stem from attempting to leave as much of the C infrastructure in place so we can port parts over in small, manageable pieces. Which is not a bad strategy but it leaves us vulnerable to issues like this where the C code is exploiting implementation details. A potential solution is teaching the C based GC to also call a Rust based GC. The Rust GC could handle whatever special bits are needed for Rust LispObjects. There are likely issues in that, but it is a possibility. Perhaps you know more here than I do @pipcet . @simon-frankau I hear you and agree, compiler support should be the goal. However, perhaps in the short to medium term we could instead leverage something like clippy? I know clippy itself doesn't support plugins (oh that would be nice!) but maybe there is a way to leverage that code and implement something? Or come up with a way to wrap items in a |
I've tried a quick pass at option 2, stopping using the Rust heap by disabling the std library and then re-exporting the parts that don't use the heap. I've put it up at https://github.com/simon-frankau/remacs/tree/no-heap Right now heap-allocating things are re-exported, but the idea would be to eliminate their usage and remove them from the re-exports. It's not fool-proof - if you pass a LispObject to another library, it might in turn place it on the heap - but the risky surface is reduced. This kind of approach doesn't address @pipcet's long-term concerns, but I think it reduces the risk of weird and hard-to-track-down bugs in the shorter term. |
It is a good and simple hack @simon-frankau. I like it until we can work out better solutions. |
I might have sounded a bit too concerned in the message above. I think a better solution will come around, and until then option 2 sounds best, and isn't as painful as I thought it would be
I think it's very rare for libraries to do that, then hand control back to the caller (so GC can run), then get called again and use the argument. Callbacks are one example of where this happens, and IIRC there's some GTK menu code that has to be very careful about that in the Emacs C code base. |
It sounds like people like this, so I'll polish up what I've got, and maybe also have a go at removing the remaining uses of Vec. |
One of the things I like about Rust is that (as long as you're not doing unsafe things) it provides memory safety guarantees. However, #845 brought home to me that it's quite possible to get live data GC'd by accidentally storing it only on the heap.
So, we're back to the C world of "If you don't want memory corruption you have to be really careful, the compiler won't keep you safe". And if there's a GC-related bug, it's likely to be a bit non-deterministic and hard to track down.
(I understand that the allocator and GC implementation is always going to need care to avoid corruption, but it would be nice to constrain that need to care to just a small part of the code base.)
I can see three approaches the project can take:
I'm quite tempted to explore option number 2, and see quite how big the changes would need to be, but I'm interested in a) what people with more experience on the code base think, and b) if anyone has any alternative suggestions.
The text was updated successfully, but these errors were encountered: