Join the discussion
Write your take first — we'll ask for email only when you're ready to publish.
- Hacker News
- This made me think and reflect, thank you.
Not so much about language design as how easy it is to take a defensive position on something we are comfortable with when it's challanged. This prohibits growth.
When someone suggests you have been doing something the wrong way or has a new idea, it's usually better to hear them out and take what knowledge you can from them, even if they weren't actually trying to help you.
Anyways, thanks again
by bubblebeard - What drives me nuts is the fact that memory safety actually has little bearing on Computer Security at large. If we had multi-level secure OSs*, with capabilities based facilities available to the user, a lost pointer would just crash the program in question, and that's it... zero side effects, ever.
I'm hoping that the next release of Sculpt, Genode's user-facing OS release, will offer this, as promised in their road map for their realse 26.08.[1] I'm hopeful that we can finally drop all these stupid layers of cruft trying to patch fundamentally insecure operating systems.
Tannenbaum was right, in the end, and Linus was wrong.[2]
[1] https://genode.org/about/road-map
[2] https://en.wikipedia.org/wiki/Tanenbaum%E2%80%93Torvalds_deb...
[*] "Multi-level secure operating system" is the required magic phrase to allow finding articles on this subject through search engines.
by mikewarot - I think the "Fil-C is safer than Rust" thing is an understandable reaction to 10 years of Rust evangelists telling people they have to use Rust otherwise they're stupid and wrong.by inigyou
- We can learn a lot about memory safety from Rust. But if we can achieve the same dream of Fil-C for other more common languages that need it, Rust's popularity will likely wane.by NBJack
- The reasonable reaction is to ignore the vocal minority.
It’s tiresome when other language communities start engaging in a battle with a vocal minority of another community.
Every language has its annoying maximalist pushers. The play is to ignore them and do what decisions are best for the language, not to let yourself get dragged down into petty language wars where nobody wins.
by Aurornis - I was not aware of the antagonism from the Zig / Fil-C people to Rust, but it makes absolutely no sense.
Like, of course you can prevent all memory safety errors by using a garbage collector. That has been known since the 90s. In fact, there was a good two decades after Java released where all the research on memory safety just stopped, because the standard answer became "use a GC". If you couldn't use GC, you were stuck with languages made prior to Java - which in practice meant just C - or the one language everyone tried to staple every new programming paradigm onto, C++.
In fact, part of why C++ became such an untameable beast of a language is because it became load-bearing for non-GC projects. Anything not in the ISO C++ standard was, in practice, something you just couldn't do in native code. Oh, of course you can't introspect structs in a compiled language, of course macros are useless and unhygenic, of course templates have to be monomorphized and bloat your binary size. And so the pressure for C++ to be an all-singing, all-dancing, all-dressed language grew.
Rust's big story is memory safety, but the more Rust I wrote, the more I realized that the memory safety is only part of the picture. Rust has a very nicely curated selection of features that allows the language to remain understandable despite the sophistication of the compiler. Memory safety is a selling point, sure, but it is also the lubricant that makes working with those features pleasant.
If you want a real complaint about Rust, it's that some features are oversimplified in ways that make certain scenarios harder and make some features way more "magic" than they should be. Have you ever tried writing Futures code without making use of the async keyword? It's nearly impossible, for several reasons; the main being that Rust's type systems cannot express self-referential borrows. This also makes returning a reference to something in an Rc or RefCell you own more difficult[0]. And there are numerous other states memory can be in that are hidden from Rust's type system. Rust can't even represent a real destructor fn. Dropping a value multiple times, or using it after it's been dropped, is explicitly forbidden; but Drop impls still can't take values out of themselves because Rust doesn't have an "owned reference" - i.e. memory you can take values from but can't deallocate.
But none of this compromises memory safety - it just makes certain things harder than they should be.
[0] Strictly speaking, there's an owning_ref crate that manages this; stdlib is also working on a "mapped mutex guard" type that would do the same thing without a dependency.
by kmeisthax - It is not universal. But imagine you enjoying a programming language (zig, odin, c, c++, …) and half the time some post/article about it comes up, 15% or so of the comments are “kindly” missionaries who just want to let you know how backwards you are, but that there is hope for you yet - as if anyone has been living under a rock solid enough to not hear about Rust.
Honestly, it gets tiresome and adds nothing useful to all these posts. And since those drive-by missionaries aren’t spreading the good word of ocaml/java/go/haskell but Rust - well, then eventually you tire of the Rust community. It has a missionary/redemption problem.
by pseudony - > Strictly speaking, there's an owning_ref crate
owning_ref is unsound and shouldn't be used. self_cell/yoke/ouroboros are much better alternatives, ableit more complex
by SkiFire13 - > Like, of course you can prevent all memory safety errors by using a garbage collector. That has been known since the 90s.
Since the 60s actually, starting with Lisp, Scheme, CLU, Cedar, Smalltalk, Cedar,...
by pjmlp - > you can prevent all memory safety errors by using a garbage collector
Garbage collection and a higher-level language that controls allocations handles 2/3 of the memory-safety problem space (using memory you shouldn't via use-after-free, or using memory you shouldn't before allocation/via arbitrary address access), but the other 1/3 isn't addressed by GC: out-of-bounds access on properly-allocated structures.
GC-or-not doesn't stop a pointerful language from addressing memory off the end of an array, and the best techniques we have to deal with that today are imperfect (but still pretty good!) compiler inference for BCE, memory protection to limit the scope of possible overreach, or slowing down runtime by inserting checks.
The rest of your points are well-taken; just pointing out that GC isn't the solution to all causes of memory-unsafety, just 2/3 of 'em.
by zbentley - > Like, of course you can prevent all memory safety errors by using a garbage collector. That has been known since the 90s.
No, it's been known since GC was invented.
> In fact, there was a good two decades after Java released where all the research on memory safety just stopped, because the standard answer became "use a GC".
Having done all of my research on memory safety after Java was released, I find this statement a little exaggerated... (e.g., https://barnowl.org/research/pubs/98-pldi-regions.pdf, https://barnowl.org/research/pubs/07-hotos-linux.pdf)
by davidgay - The thing that has changed is that there are spaces where security is being taken more seriously, and C's memory unsafety became a deal breaker there. I do think that providing a mechanism to run existing C software that isn't performance sensitive in a way that mitigates its limitations is very worthwhile.
I think the "static analysis" and the "runtime checks" approaches are complementary, not in opposition, making any noise around having to choose one or the other moot.
by estebank - > I was not aware of the antagonism from the Zig .. people to Rust, but it makes absolutely no sense.
Lol, have you ever watch Andrew Kelley speak? I've only seen 3 or 4 talks he's given, but he frequently makes not-so-subtle digs towards Rust. Zig's home page prominently displays "Focus on debugging your application rather than debugging your programming language knowledge" which sounds horrible to me, but is clearly an anti-rust statement. Competition is good, and Rust and Zig cater to different people, but when the primary personality behind Zig is leads the way, it shouldn't be a surprise that some tribalism-influenced followers lean hard into it.
by manithree - If I want a memory-safe, garbage-collected language, I have a ton of choices already, and many of them are safer in other ways than either Rust or anything derived from C (richer type systems make programs safer). Not to mention being prettier and more ergonomic. The huge advantage of Rust is that it's memory-safe with no GC; it makes your timing and memory occupancy much more deterministic at those times when you have to care.by Hizonner
- Something that is important to me is that it's caught at compile time. A memory issue is a logic bug. Fil-c simply moves that from undefined behavior/security issue/incorrectness to a crash. That's better than what it was. But I generally don't want my programs to crash. Having memory safety at compile time is much more worthwhile imo.by rowanG077
- As a Rust fanboy, I have to concede that Rust also doesn't have pure compile-time memory safety. Some checks are runtime there as well, in particular most of bounds safety.by muvlon
- It’s the exact opposite for me. Catching it at compile time is great, but the most important thing by far is that it’s caught somewhere instead of creating a security issue.by wat10000
- I don't think you need to be an absolutist or only use memory safe languages but it's very obvious that we need to do a whole lot better than we actually do. Rewriting in Rust or any other language is one way to do that, but not a perfect one. I'll accept C++ when most C++ software has 1 in 50 chance of an RCE and not just a 1 in 50 chance of a known RCE. I think we can get there but we are not currently there.
Coreutils has a good track record. Ffmpeg doesn't. They should have rewritten ffmpeg in Rust, not coreutils.
There are other approaches though like formal verification.
by inigyou - >They should have rewritten ffmpeg in Rust, not coreutils.
Wait for an AI company to promote their new model by porting the entire ffmpeg to Rust (half ironically).
by GaggiX - If you go by this metric (has a RCE and not known to have RCE), I'm pretty sure the actual statistics are more like 1 in 2, at least. And probably more than one RCE.by afdbcreid
- ffmpeg is actually asm and for a good reason - it has to go fucking fast or else media playback will take too much resourcesby bpavuk
- Trying to figure out Fil-C's "inviscaps".[1]
When you allocate space with Fil-C's "malloc", some additional bounds checking data precedes the space the program gets to use. Pointers are "fat pointers", with a pointer to the beginning of the buffer and a pointer to someplace within the buffer, allowing ordinary C pointer manipulation.
There's much new verbiage around this. But it's roughly the same idea as GCC "fat pointers".[2][3] So it's not a new idea. It's one that's been tried several times, but never caught on.
There's a performance penalty. Especially if the compiler can't hoist the checks out of loops.
[1] https://fil-c.org/invisicaps
by Animats - Invisicaps are not exactly fat pointers.
Fat pointers show up inline in memory, which has a bunch of problems:
- sizeof(void*) changes
- either you let the bounds get corrupted by bad casts, unions, and other issues, or you impose restrictions that prevent unions from working compatibly, or you end up supporting unions by having issues with races, or you need special hardware. Invisicaps sidestep all of those issues
by pizlonator - Pizlo is not a memory safety absolutist. His rhetoric towards rust is a tactic specifically designed to draw more attention to him and his project. It is amplified by people who already had a bone to pick with rust and take joy in giving rust folk "a taste of their own medicine," so to speak. Articles like this are taking the bait.
- What a weird take.
I think the limits of Rust’s memory safety are interesting to discuss, as are the limits of Fil-C’s perf and practicality.
It’s best to discuss these things rationally, rather than accusing folks of trying to draw attention
by pizlonator - Personally, I see these language fights as being a bit pointless. They are trying to optimize at the wrong layer. Unless one is working with a dependently typed language, which requires a proof assistant to discharge type checks, then it's all just a question of where you make the trade-off. Don't care about memory leaks or deadlocks as part of your soundness guarantees, but can't have GC? Use Rust. Okay with runtime overhead to verify checks? Consider fil extensions.
If you want to go deeper, skip the language wars entirely. Tooling does what these languages can't do. I have had great success model checking C with CBMC. Not only does this prevent memory safety issues (including memory leaks), but this also prevents deadlocks. Bonus: you can write user contracts and invariants to verify that every execution path of a function fulfills these contracts and invariants.
Kani comes close with Rust. It doesn't yet have decent concurrency support, but there is nothing that prevents this from being added in the future. The ability to write custom contracts and enforce custom invariants more than makes up for its lack of concurrency support. Similar technology could be used or adapted for Zig or C++.
Use whichever language you like. Just, please look into model checking it. The technology scales just fine, once you get over the learning curve and learn how to use compositional verification.
by nanolith - This is perhaps a different take, but one reason I love Zig and C is because I've learned how to reason in pointers. I've worked with Rust in the past on a ~12,000 LOC side project, so I was all in with tree ownership and XOR mutability. But it turns out there's all sorts of delightful data structures that you can only express with unsafe in Rust. Intrusive doubly linked lists are the coolest thing ever. The fact that I can have a LRU cache that changes what's at the front by shuffling some pointers, while still keeping stable addresses so the hash map stays stable? That's freaking cool. Atomic operations with pointers for linked lists is really slick for implementing an allocator's free list between threads. Being able to walk a live heap using a breadth first search by just... following pointers, made the elegance of Dijkstra's algorithm come alive.
Now, maybe I'm only running into these algorithms because these are the problems I'm running into, but in the Rust community I consistently got the message that linked lists were a legacy data structure. In some cases they are, but when they do apply they do so brilliantly.
I know working in Zig leaves plenty of room for memory unsafety. Perhaps that's a bad thing. But I'm implementing an interpreter, and these algorithms are essential for it to run fast. I really do need to be aware of where every allocation happens, and what instructions the computer is running. So for now I stick with Zig, even though I know I'm opening myself up to memory exploits.
by smj-edison - Given your performance concerns, I'm imagining you're unlikely to run Zig-Fil in practice, due to the GC overhead?
- Sadly due to cache friendliness, current conventional wisdom is that linked lists are so slow that a dynamic array of pointers is almost always faster even in cases when you'd think linked lists would be faster, such as frequent insertions in the middle.by inigyou
- Linked lists are cool but they are terrible for cache performance, so their apparently elegant performance characteristics are often illusory. And hybrid data structures which get you the best of both worlds are quite complicated to implement. I think that's why there's a general pressure against using them unless you have a very specific reason (and ideally some measurements) to demonstrate that they are a good option.
(part of this I think is some C teaching which tended to overemphasize linked lists because they are useful for teaching the concept of pointers, which gave a lot of people learning C the impression that it should be the default way to represent a list of objects, when it's far more the exception than the rule)
by rcxdude