5 ms·
Thanks very much for this. (Some bits have been elided for brevity and to avoid the HN comment length limit; do note I understand the points you've made in spi
by i336_ 10y ago
Thanks very much for this.
(Some bits have been elided for brevity and to avoid the HN comment length limit; do note I understand the points you've made in spite of shortening some parts)
> The difference between regular bugs in memory-safe programs and memory-safety bugs is that with a regular bug your program is still evaluating the code you wrote; (...) [t]hese are frustrating, but can usually be understood once found by established debugging techniques like bisecting a codebase with a test case.
Right. (It's sad the only truly generic way to apply this approach is with fuzzing.)
> With a memory-safety bug, (...) it's effectively impossible to mitigate the impact on your code of memory safety bugs outside your code.
Ooohh. I see - faulty image parsing letting you break out of Chrome, or faulty font parsing letting you run amok in the NT kernel (yay!).
> As noted, Rust is not, as a whole, memory-safe. (...) But, in Rust, if you see misbehavior you do not have to audit your entire codebase. You only need to audit the code explicitly marked as unsafe. The vast majority of computation in Rust is outside of unsafe blocks, and using unsafe in the middle of a complicated, subtle algorithm raises big warning bells in code review.
That makes sense.
> With respect to "C and other languages [having] similar issues", I don't think this is the case. Remote native code execution is a security issue only present in memory-unsafe programs.
It's so sad the Burroughs-style architecture (https://news.ycombinator.com/item?id=14073079 https://news.ycombinator.com/item?id=14073079) fizzled out :(
> We do see remote (high-level) code execution vulnerabilities in programming languages with "eval"-like faculties, but it's not hard to audit your code and all its dependencies for calls to the built-in "eval", whereas auditing C code for memory safety is incredibly difficult.
Unless it's JavaScript - https://news.ycombinator.com/item?id=14013155 https://news.ycombinator.com/item?id=14013155
(Related: http://stackoverflow.com/questions/42776357/can-i-effectively-use-transpilation-code-tokenzation-regeneration-a-vm-or-a-si http://stackoverflow.com/questions/42776357/can-i-effectivel...)
> All of this is in some sense a consequence of the principle of least privilege: we want to make the world more secure by avoiding having an omnipresent "do absolutely anything" escape hatch, so that we can trust modules in proportion to the privileges they need. (...)
Right. On the one hand that [escape hatch mentality] gets you Symbolics Lisp; on the other hand those Lisp machines never ran banks or multiuser systems :P
> The other half of Rust is that having algrebraic datatypes and a good typesystem helps you help yourself avoid many logic mistakes, and having an expressive language with generics helps you write less code (which correlates with having fewer bugs).
The only problem there is that the verbosity of the code can cause oldschool hackers to flounder: http://esr.ibiblio.org/?p=7294 http://esr.ibiblio.org/?p=7294
> This is why Haskell programmers like to claim they see fewer bugs than other languages. It's much harder to make an objective argument here, because availability of tools for preventing bugs isn't the same as lack of bugs.
Can't disagree there. Objectivity FTW.
> There are C codebases with fewer bugs than Haskell codebases; pure bug count depends on a multitude of factors in the development process and only formal verification can prove your program to be correct relative to its specification.
> And then your specification still might not mean what you wanted it to mean! There aren't any silver bullets, but Rust is a useful tool that you should consider making part of your toolkit, and there's been a lot of work to try to make it able to do all the things people do in C.
Thanks for this, it was an interesting read.
If anything, Rust badly needs a rockstar documentation team who can canonically communicate "the state of 4 minutes ago!" and keep everyone updated in real time. A herculean effort, most definitely, but it would ensure people had correct ideas about the language from the start, which would be cool.
I also think I have a theory as to why the parent commentator ("Except compilers are also...") has the views they have.
Rust requires you to be extremely verbose in describing every last iota of abstraction (and you have to have the right number of levels) - you can't just start banging around in the kitchen with random bits of hardware like you can in C, or hammer strings together like you can in Perl, or do Python's "executable pseudocode" thing, etc. You have to be neurotically specific (it feels like it when coming from the familiarity of another language that most decidedly does not feel like that).
I think that oldschool people encountering this see it as "too much work", because for the level of effort required, they expect the compiler to do more work for them than it's doing (for example, wrangling cyclic data structures). And so they go "I have to do all this?! And I only get that as a result?!" and throw their hands up in the air and find it hard not to criticise.
So this folds back into the documentation problem - people are collectively memoizing the "Rust is awesome!" from all the impressionable foghorn types. The foghorns need to be turned down a little and the nuance made a little clearer.
PS. I must admit that when I saw your "x->name" my brain immediately went "wait, what's x's current value?" - I'm still learning C (I understand the basics, but I'm still slow with it in many areas), and I'm happy I instinctively reacted like that :)
- gue5t 10y agoRelated to "Unless it's JavaScript", what I mean by "not hard" is that a conservative static analysis can determine whether your code can possibly reference the built-in eval function. A static analysis can't tell whether a eval will be run if it is present (halting problem, and there are escape-hatches like filesystem+exec()) but I think it's very reasonable to expect people to forbid them outright in high-assurance code. Anecdotally, I've rewritten fair amounts of code from Go to Rust and it seems like Rust takes about 60% the lines of Go, which is mostly due to library reuse for control-flow constructs (higher-order functions rely heavily on generics to be usable and not merely confusing footguns) and simplified error handling. The biggest pain point when porting is usage of goroutines, because these dictate the threading and communication architecture of your Rust code, and unlike goroutines it isn't cheap to spawn large numbers of real threads. This would be better with a coroutine library, but I haven't tried that approach in a ported codebase. I do think explaining the language clearly and precisely is a big challenge and hope we can make it happen. It's true that Rust forces you to be explicit and precise in many places C doesn't, but coming from a long time of programming C I loved to see that Rust was enforcing universally the guidelines that C projects slowly develop after years of developer experience: explicitly state memory ownership (in comments, in C), explicitly state which shared memory is protected by which locks (again, in comments or variable names in C), call destructor functions for all live local variables before returning from a function (done automatically by the Rust compiler), and so on. Rust is, in many ways, shorthand for well-written C. It makes you jump through hoops to express many sloppy C practices. If you're just learning C, after you understand the basics I think the most important thing to understand is the abstract machine around which the language is defined; that's how you learn to reason about UB and which optimizations and transformations compilers will or won't do, along with how to guide the compiler to the translation you want. C isn't defined against a single huge byte array of memory, and pointers aren't indices into such!
- i336_ 10y agoSorry this reply took a bit long (if you see it at all) - had a bit of a notification failure. > Related to "Unless it's JavaScript", what I mean by "not hard" is that a conservative static analysis can determine whether your code can possibly reference the built-in eval function. (...) Oooh, like that. I get what you mean now. > Anecdotally, I've rewritten fair amounts of code from Go to Rust and it seems like Rust takes about 60% the lines of Go, which is mostly due to library reuse for control-flow constructs (higher-order functions rely heavily on generics to be usable and not merely confusing footguns) and simplified error handling. Hmm. > The biggest pain point when porting is usage of goroutines, because these dictate the threading and communication architecture of your Rust code, and unlike goroutines it isn't cheap to spawn large numbers of real threads. This would be better with a coroutine library, but I haven't tried that approach in a ported codebase. I'm curious if this is because there's no consensus on which coroutine library to use yet. The example I linked last message (http://esr.ibiblio.org/?p=7294 http://esr.ibiblio.org/?p=7294) also whined about Rust not having a select() primitive or equivalent functionality in the core language - https://github.com/rust-lang/rust/issues/27800 https://github.com/rust-lang/rust/issues/27800 remains open since Aug 2015 as of my writing this comment, but I don't know if there are any standardized (ideally stdlib-level) solutions known outside of this communication channel. > I do think explaining the language clearly and precisely is a big challenge and hope we can make it happen. Cool :D > It's true that Rust forces you to be explicit and precise in many places C doesn't, but coming from a long time of programming C I loved to see that Rust was enforcing universally the guidelines that C projects slowly develop after years of developer experience: explicitly state memory ownership (in comments, in C), explicitly state which shared memory is protected by which locks (again, in comments or variable names in C), call destructor functions for all live local variables before returning from a function (done automatically by the Rust compiler), and so on. That's fair. I get the impression Rust's vision is to be the go-to language for low-level enterprise-scale (ie, long-term) stuff, while also being accessible and suitable for hobbyist scripting. I can completely appreciate that. > Rust is, in many ways, shorthand for well-written C. It makes you jump through hoops to express many sloppy C practices. That's pretty cool. :> > If you're just learning C, after you understand the basics I think the most important thing to understand is the abstract machine around which the language is defined; that's how you learn to reason about UB and which optimizations and transformations compilers will or won't do, along with how to guide the compiler to the translation you want. I've only very recently started to notice this and grasp the importance of the difference between the hardware and what C abstracts that hardware as; thanks very much for the recommendation, I'll focus more closely on it. On that note, I find it remarkable how platform-agnostic yet hardware-accessible the C abstract machine is; I'm not sure whether to be mildly scared at the engineering ingenuity of the language or merely duly impressed that the developers just happened to stumble upon a really good design :)