4 ms·
I'm curious if Rust would have prevented the memory correctness errors assuming it replaced Zig in this scenario. It sounds like the vast majority were due to Z
by schmichael 1y ago
I'm curious if Rust would have prevented the memory correctness errors assuming it replaced Zig in this scenario. It sounds like the vast majority were due to Zig/C interactions which makes me believe Rust would have had the same issues, but as a Go developer I am only guessing. I'm curious if there is a language that provides more tools to ensure correctness even when you're interacting with a huge amount of C.
- WD-42 1y agoI think one of the main points of the article was about how shockingly few memory issues they have encountered. He talks about how great of a fit zig + valgrind is.
- schmichael 1y agoIndeed, but I'm curious about the second class of memory correctness issue he mentions: > 2. All other memory issues revolved around C API boundaries. Is this something Rust, or any other language, has the ability to prevent any more than any other language? Or once you introduce a C API boundary is it back to tools like Valgrind?
- wofo 1y agoHaving worked on a few Rust projects that interface with C libraries, I think your last question is a good summary: once you introduce a C API boundary it's back to tools like Valgrind. Maybe you could even say Zig is at an advantage there, because tools like Valgrind are considered part of the game, whereas in Rust they are way less commonly used (pure-Rust codebases don't need anything of the sort, unless you are using `unsafe`).
- sbt567 1y agoI vaguely remember that there is a new language that promises "Safety across FFI boundary", but can't recall the name
- NobodyNada 1y agoIn general: whenever you call into C, you get all the safety of C, because C code can trivially have memory corruption bugs that corrupt memory "belonging" to Rust as well, inducing undefined behavior across your whole program [0]. In addition, it's often considered permissible for C APIs to exhibit undefined behavior if their API contracts are violated. This means that a bug in Rust code that calls into a C API incorrectly can (indirectly) cause undefined behavior. For this reason, all FFI calls are marked unsafe in Rust. The typical approach to using C libraries from Rust is to create a "safe wrapper" around the unsafe FFI calls that uses Rust's type system and lifetimes to enforce the safety invariants. Of course it's possible to mess up this wrapper and have accidental undefined behavior, but you're much less likely to do so through a safe wrapper than if you use the unsafe FFI calls directly (or use C or Zig) for a couple reasons: - Writing the safe wrapper forces you to sit down and think about safety invariants instead of glossing over it. - Once you're done, the compiler will check the safety invariants for you every time you use the API -- no chance of making a mistake or forgetting to read a comment. [0]: This could be avoided/mitigated with some kind of lightweight in-process sandboxing (e.g. Intel MPK + seccomp) to prevent C libraries from accessing memory that they don't own or performing syscalls they shouldn't. There's some academic research on this (and I experimented with it myself for a masters thesis project), but it generally requires some (minimal) performance overhead and code changes at language boundaries.
- troad 1y ago> The typical approach to using C libraries from Rust is to create a "safe wrapper" around the unsafe FFI calls that uses Rust's type system and lifetimes to enforce the safety invariants. Calling it a "safe" wrapper, when that safety is entirely dependent on (a) the correctness of the hand-written wrapper, (b) the safety of the underlying FFI code, has always been a huge stretch of terminology. It's more like a veil of safety, so we can shield our modest eyes from impure code that flaunts its unsafeness. Rust has no magical ways of turning unsafe code safe, nor is it in any way special in being able to create statically-verifiable abstractions around an unsafe core. Don't get me wrong, Rust is memory safe when used as a cohesive system, and I would encourage its use as such where memory safety is desired. But the idea of "safely" wrapping unsafe FFIs reminds me of the idea of packaging underwater mortgages into mortgage-backed securities and selling them as a safe investment.
- mitchellh 1y agoHi @schmichael ;) Rust would've prevented one. The rest Rust wouldn't have prevented since as you already noticed, it was in the boundary layer and semantics of a C API. It would've only been as safe as the Rust wrapper. One argument is that the richer, more proven ecosystem of wrapper libraries may have prevented it versus my DIY wrappers. The one Rust would've prevented was a simple undefined memory access: https://github.com/ghostty-org/ghostty/pull/7982 https://github.com/ghostty-org/ghostty/pull/7982 (At least, I'm pretty sure Rust would've caught this). In practice, it meant that we were copying garbage memory on the first rendered frame, but that memory wasn't used or sent anywhere so in practice it was mostly safe. Still, its not correct!
- schmichael 1y agoHey Mitchell! Leave it to me to bait the comments. :) Thanks for validating my assumption that once you introduce a big blob o' C all bets are off and you're back to Valgrind (or similar tooling). > One argument is that the richer, more proven ecosystem of wrapper libraries may have prevented it Yeah but where's the fun in that? ;)
- pornel 1y agoRust has safe and reliable GTK bindings. They used gir to auto-generate the error-prone parts of the FFI based on schemas and introspection: https://gtk-rs.org/gir/book/ https://gtk-rs.org/gir/book/ Rust's bindings fully embrace GTK's refcounting, so there's no mismatch in memory management.
- ericbarrett 1y agoDo you mean gtk-rs (https://gtk-rs.org/ https://gtk-rs.org/)? I have done a bit of programming with it. I respect the work behind it, but it is a monumental PITA - truly a mismatch of philosophies and design - and I would a thousand times rather deal with C/C++ correctness demons than attempt it again, unless I had hard requirements for soundness. Even then, if you use gtk-rs you are pulling in 100+ crate dependencies and who knows what lurks in those?
- 1y ago
- deleted 1y ago[deleted]
- ozgrakkurt 1y agoIt is so much more difficult to write c bindings in rust. Maybe they wouldn’t even be able to write gtk bindings in rust
- steveklabnik 1y agogtk bindings in Rust have existed for like, ten years.
- ethan_smith 1y agoRust would face similar issues. Its safety guarantees only apply within Rust code; the FFI boundary with C/GObject is inherently unsafe and requires manual lifetime management. Rust's borrow checker can't verify external code's memory usage.