>These are how I classified the bugs. If I’ve got something drastically wrong let me know.
I'm really happy to see the data behind the claim! I've been slowly desensitized to opinions masquerading as unsourced supporting graphs of dubious provenance.
It's so simple, but kudos to the author for the transparency.
When Daniel wrote "C is not the primary reason for our past vulnerabilities", he may or may not have been right. But he sadly did not back that up with easily verifiable, refutable, data.
Data is like a ray of sunlight. Instead of arguing high-level opinions, let's argue the data
>Speaking at the BlueHat security conference in Israel last week, Microsoft security engineer Matt Miller said that over the last 12 years, around 70 percent of all Microsoft patches were fixes for memory safety bugs.
Of course, Rust isn't the only language that tries to address memory safety, but it is one of the few that does so while retaining the performance of C.
Microsoft's current security advisory is to use C#/F# (including their newly introduced low level capabilities up to .NET 5), Rust and then C++ alongside Core Guidelines.
However the same Microsoft has backtracked in their rejection of C, adding support for C11 and C17, replaced the C++ userspace drivers framework with a C one, and despite all security sales pitch for Azure IoT, they ship Sphere OS and RTOS with a C only SDK.
No, Data does not get to decide what cUrl is implemented in, Who ever implements it gets to decide.
If you want to prove that RustUrl would be better then cUrl, you will have to implement it and prove that its actually better, by taking users away from cUrl. Decisions are made by those who make things not by those who have opinions, even if they are backed up by data.
Daniel doesn't have to defend his choices, because you can write your own if you don't like his.
That is true. And as the post mentions, Daniel did decide to allow some Rust into the tree, years after he wrote that post. Sometimes people change their mind. It's often a good thing!
Changing your mind is great! I do support, Daniels choice to do what ever he wants in what ever language. My statement was not against Rust, It was against the idea that software development is done by writing think peaces online.
I refer you to the Linux Kernel mailing list FAQ 15-6, that I think makes my point:
It is true that code can convince, but often, the written word matters too.
For example, the Linux kernel is considering accepting Rust in tree. While that is predicated on people writing the code and demonstrating its value, even getting to that point has required a lot of communication and convincing. It is often considered polite in open source projects to attempt to build some consensus before sending large patches upstream.
Sure, but what the author of this article is arguing is that someone who has spent a lot of time and effort making something should throw all that work in the trash, and start over, because they did it wrong, I dint think that is either polite or constructive.
One of the things the author neglects is the ease of use of newtypes in Rust. This can actually alleviate a lot of parsing issues, by making it impossible to use stuff without parsing.
An example of where I've recently done something like this is my sparse linear algebra code. I have distinct types for column and row vectors for a matrix, so that if I want to right-multiply A with a vector, the input has to be a column vector and the output has to be a row vector. Similarly, if I want to left-multiply A with a vector, the input has to be a row vector and the output has to be a column vector.
>there are also a decent number of other bugs that come from cURL doing ad-hoc inline character-by-character parsing of just about everything, whereas in Rust you would probably use a library to fully parse things.
This was my initial charitable interpretation too, but the linked URL is actually to a specific url parsing crate. That's definitely in cURL's wheelhouse.
cURL isn't an abstract parsing library in the notion that is intended here. Rust has some libraries that give you pretty high level abstractions for generalized parsing that are also incredibly performant - something that's not really a thing in C.
That jumped out at me too. cURL is one of the most ubiquitous libraries out there. It's worth keeping its dependencies to an absolute minimum, even if it means having to rewrite a function here and there.
I really should learn Rust. I am just nostalgic for C because C makes me feel like I am doing something closer to what the CPU works with. I know there are several layers underneath all that, but with C you can do all manner of dangerous things that by any means you shouldn’t be allowed to do. I have used it for a few projects over the years but lately the only place I really get into it is programming Arduinos or similar. I am sure sooner or later we will get a good toolkit for a language that both does proper memory management AND can allow you to do all the things you can do with C on a microcontroller, but so far I haven’t seen that.
Also, I have it on my TODO to go back and redo the Capture the Flag challenges from like 10 years ago that dealt with things like stack overflows. I had a ton of fun working on those and it would be fun to revisit them. Anyone got a modern version of something like that?
Thanks! I spent a couple of hours looking at it and it looks like a really cool language. Unfortunately no build targets for the ESP8266/ESP32 which is my current t microcontroller of choice but the next time I try to put together a project that targets a different architecture I’ll try Zig out!
I have an account there according to my password manager! But like Gandalf I have no memory of this place. Very cool, I know what I’ll be doing tomorrow, thank you!
This is counting the number of bugs, but what about the severity?
https://curl.se/docs/CVE-2018-1000007.html is a logic bug that may cause sensitive headers to be sent to the wrong host on redirects. It's slightly obscure, but I can imagine what an exploit looks like.
https://curl.se/docs/CVE-2018-1000120.html is a memory bug that lets you write a single null byte out of bounds. That's a security issue, but exploiting it seems less straightforward. (Though maybe it is more dangerous than the other one on net? I don't know enough about these issues to say.)
It could be that Rust would prevent half the vulnerabilities yet prevent much less than half the danger caused by vulnerabilities.
Do note that the "single out of bound NULL byte" vulnerability has famously caught people off-guard in the past due to it being unexpectedly exploitable =)
Those kind of exploits are thankfully getting harder with the many layers of mitigations we have today, but trying to predict which memory bug will or will not be exploitable is a very unintuitive and inadvisable exercise.
So you're saying Rust would make it more secure, but is not a magical panacea that prevents all security holes? I mean...okay. Still seems like a good reason to write it in Rust?
I'm only saying that Daniel's claim that "C is not the primary reason for our past vulnerabilities" might be basically right, even though the article says it's wrong.
I know I’m not reacting to the substance here but thats a terribly designed diagram. If the goal is to compare these values then why don’t they all start at the same level? This stacked exploded bar chart is unconventional and hard to parse at a glance. Dare I say even missleading how the author’s prefered option (the “yes” collumn) is towering above all the other numbers even though it is roughly head to head with the “no” collumn. (47 vs 42).
C libraries/applications like these, which have many memory and logic bugs, should be written in SPARK. It can fully prove that your code is correct. The latest version of the SPARK tools can also handle ownership of pointers [1] (scroll down a little to the ownership_transfer.adb example) So RIIS it is! ;)
> Rust proponents may seem overly zealous and I think this has led to a minor backlash of people thinking “Rust can’t be that great surely; these people must be confused zealots, like Trump supporters or Christians”. But it’s difficult to argue with numbers like these.
These are stereotypes. There's far more variety within constituents of a political or religious group (including atheists) than between them. Arguing that one group is more "zealous" than another is almost certainly untrue for any meaningful kind of comparison (e.g., Muslims have more extremists than other groups, but we would rightly balk at generalizing Muslims as extreme). At best, these comments are meaningless; at worst, they incite hate and divisiveness (predictable whataboutism: "but Trump is divisive! Why can't we be divisive toward his supporters?!"--yes he is divisive, but he shouldn't be our moral standard).
Huh!? I am not happy that he did not put costco shoppers in that list .. /s
Yes, that was a needless statement that distracts but you know what, there is no point getting too hung up on things like these from readers perspective too.
It's a foolish, aggressive analogy that needlessly distracts from the topic at hand, regardless of any validity it may or may not have. There are far better ways of communicating the intended message.
Either way, this is definitely not the point of the post. It seems worthwhile to make an effort to avoid rehashing highly controversial, unrelated topics -- even if the article accidentally baits us into it.
Sure. Fits. Are you looking for support or something?
The language was unnecessary and unprofessional, but those are that only ways it was wrong. If I were writing something in a personal context where such opinions were not out of place rather than a technical article, I would absolutely apply that characterization.
You don't have to. But Don't be so baffled that anyone else does.
Trump supporters and Christians: you'll be fine. Not everyone in the world will respect you, and some may disrespect you specifically for that part of your identity. Try to live and let live.
A lot of the Actix-web drama was the author refusing to replace unsafe code with safe code that performs equally as well. After the creator quit, the community took over and removed a lot of the unsafe code present.
I checked a few, and they mostly look like cases of non-performance-critical code that just happens to have some fiddly, slightly-wrong memory-handling logic -- which Rust would, indeed, make much harder to mess up with little or no runtime penalty.
curl is in widespread use while Actix remains fairly obscure, so this isn't a particularly good comparison. Is there even a Rust project that publicly discloses it's bugs in the same manner as curl?
I never quite understood why an ideology should be except from criticism so long as it be popularly called a religion.
Evidently one can insult Rust evangelists, why do many consider the arbitrary classification of “religion” so special? Especially when it seems a common criterion to call something a religion is “at least part of the belief must be provably false.”. — wakarimasen lol.
The author doesn't criticize an ideology; he insults Christians. I imagine Hacker News would be less tolerant of those remarks if they had referred to Jews or Muslims as "confused zealots".
What is a minority and majority depends on where one lives, of course.
And naturally, the moralist is quick to loose such a perspective that not the entire world lives in his own back yard, it seems. — perhaps if he were more aware of how vast and different the world is, he would have been more doubtful of his own moral convictions.
While, of course, you can find specific locations where they aren't the majority, you can also find specific locations, in the US, where white people aren't the majority.
That doesn't change the equation when talking about punching up vs punching down.
Neither is really relevant to the post; he's clearly using hyperbole to describe Rust zealots in other peoples' minds.
Ah yes well, if it work as such then I suppose since Asia is the continent with the plurality number of inhabitants on the planet then we can say all sorts of nasty things about Asians, but about the inhabitant of any other country would be foul play.
Somehow, I feel you simply speak of the plurality of your own back yard.
The author wasn't asserting Christians and Trump supporters were actually zealots; the author was saying Rust evangelists are often dismissed in the same way, dismissed for being "confused zealots", when in fact, there may actually be some merit to be found. There are certainly things said by Christians and Trump supporters I don't disagree with. That doesn't make me one, but I am an unapologetic Rust evangelist, so...
That seems to be a rather empty difference. — I can criticize Rust evangelicalism, but not Rust avangelicals?
And perhaps H.N. would have, but your argument is with me, and not “Hacker News” and I make no such distinction, provided, of course, that by “Jew” you mean “Judaist” and not “person whose maternal parent is a Jew”.
> On-Topic: Anything that good hackers would find interesting. That includes more than hacking and startups. If you had to reduce it to a sentence, the answer might be: anything that gratifies one's intellectual curiosity.
The problem with security in Rust is that the language emphasizes the reduction of memory bugs. The resulting code then creates an increased cognitive load which can make other bugs more likely.
Therefore, use Rust if you really have to. Otherwise, tools like automated garbage collection are a much better way to reduce the likelihood of bugs.
The cognitive load is just temporary. I can say that after writing it full-time for about half a year, and dabbling in and out of it for a bit longer, I've gotten as good with Rust as I was with JS or TypeScript.
I've seen people learn Rust as their first programming language, and it fills me with joy that the next generation of programmers won't have to build up this vault of apocryphal knowledge I've had to over the years. Or, at least, not the same one. And hopefully not as large.
I've also found Rust to be a very pleasant application development language. As a former NodeJS developer, I've been able to replace Express with Warp and Electron and React with Iced. It's not ready for all things, but it's ready for a heck of a lot. And the question of "what's possible" has broadened so much due to work by the community in even just the past year, I really think the majority of all other applications, including web frontend (cargo web), servers, desktop apps (iced), and mobile apps (cargo mobile), can be reasonably implemented in most part entirely in Rust within only a few years.
> the language emphasizes the reduction of memory bugs
That's not really true: Rust's borrowing and ownership apply to most kinds of in-program resource ownership and aliasing, not just memory.
> The resulting code then creates an increased cognitive load which can make other bugs more likely.
I'm not saying you're wrong, but I'd like to see any evidence for this. Personally, I'd expect the opposite to be true: knowing whether any given object is non-exclusively borrowed, exclusively borrowed, or owned at any point in the program sounds like very useful documentation for people reading the code.
From skimming some Rust code now and then, it seems to me that Rust programs look completely different at least. While C programs focus on creating simple data structures and getting the task done with as few memory operations as possible, in Rust I've dominantly seen use of types, memory/resource safety patterns and external libraries. My theory is that this removes direct understanding what happens and instead shifts the focus on how to get the task done while not violating the type system rules. In both cases, what the programmer minimizes in the first place might be the lines of code or maybe "code complexity". (Assuming programmers tend to do what most directly leads to completion of the programming task).
I'm not in a position to claim that this theory is actually true, and I won't take a stance which is "better", but personally the former is much more appealing to me, for purely aesthetic reasons.
Rust provides a good balance between performance, correctness, and ergonomics. It's called the "Goldilocks language", because it's not too slow, it's not too unsafe, and it's not too difficult.
Also, much of the tooling I used to add to projects in other languages is either built-in and commonly used (test, fmt), or easily added to cargo (edit, bench, web, mobile).
> My theory is that this removes direct understanding what happens and instead shifts the focus on how to get the task done while not violating the type system rules
In my experience it is in fact still a requirement to understand
what's happening in order to write clean and fast Rust code. It
is possible to satisfy the compiler using a lot of clone() calls
and similar shortcuts, but once you understand what data
structure is allocated when and where and how the whole
ownership principle works in practice you can suddenly avoid a
ton of unnecessary heap allocations and other pitfalls. I'd say
my experience with Rust improved a lot once I started grasping
what's happening in memory and why certain syntax elements
exist, as this makes fixing compiler errors more intuitive and
less a blind trial and error session with the borrow checker.
Some of Rust's syntax can look weirdly unfamiliar at the
beginning, but everything is there for a good reason. Nothing is
done implicitly, and much of the pattern matching and
Option/Result related stuff is Rust's way of replacing the
concept of `null` with thoroughly type-checked expressions.
I find this description unsatisfying. The "use of types" makes applications easier to understand and cleaner for example. Just a generous use of enums helps with some kinds of logic errors as well and ensures more expressive code. (==1 vs ==Match::Domain)
I use enums in C, too. And the problems with C enums that people complain about don't apply for me. That's not what I mean by "use of types". What I mean by it is significant "programming in type language" as opposed to "in code language". Programming in type language I find unappealing because it is very indirect, implicit, and typically achieves very little per line of code.
Enums in C are just ints with names. They're error prone and not type checked. You can always use 0 instead of a name and it will work. You can use TLSv2 instead of ExterminateHumans and it will also work.
> What I mean by it is significant "programming in type language" as opposed to "in code language".
I honestly don't understand what you mean by this.
Okay so, the issue here is that you two are speaking past each other. Enums in Rust are more than enums are in C. So this conversation is something like:
Them: I like sandwiches.
You: I get sandwiches from McDonalds, they're great.
Them: Yes, but those are burgers. (The implication being that there are also other kinds of sandwiches.)
You: Yes, burgers are good.
You're not wrong, but you're kind of missing what they're saying.
Enums in Rust can be like enums in C, but they can also be tagged unions. Furthermore, Rust won't automatically cast an enum to an int, so it is a bit harder to make mistakes, even if you're using the C-like ones. That's the advantages they're speaking about. Enums are good and useful in C, it's true. That's why Rust added stuff to make them even more useful.
Yup, plus the other uses have their own implementation. If you're doing arithmetics, in rust you probably want a constant. If you want a bitmask, there's bitfield crate (or a struct/enum with bitwise ops implemented).
Keep in mind that just because you like something, doesn't make it good, and that's starting to get more and more important in these days where software is used for everything, including things really depend on.
This seems like an unlikely claim, do you have any numbers to back it up?
If having memory errors being compile time errors instead of runtime error leads to more logical errors due to complexity. Wouldn't that imply that using other types of complicated checkers also leads to more logical errors, for example static analysis software or valgrind?
Rust's type system with regards to C and that of many other languages certainly helps to avoid logic bugs as well.
A simple difference would be that, for instance, in Java every object is nullable, whereas in Rust, this is only so when it be declared as such, and the type system requires one to in some capacity first verify of a nullable type that it isn't null, before something meaningful can be done with it.
Fully idiomatic GUIs are still an open problem in Rust, but I wrote a Win32 MDI application in Rust last week. It just makes you feel gross, but it's the same as other native code.
Linked Lists are easy. _Doubly_ linked lists can't happen without Rc or unsafe, but that's fine.
And yes you can create types for domain units, while controlling the combinations like that, and can go deeper in that sort of idea than C and C++.
1. Use a binding to a library or write your own. Gtk bindings are probably the most mature option, but there are some exciting in-progress ones.
2. Yes. One is even provided in the standard library, if that suits your needs. However, most people don’t use linked lists because other data structures are near-universally better.
3. Rust doesn’t have classes, but you can do something similar. The name is the “newtype pattern.”
Yeah, you can do newtypes (or just defining new types), in addition to Structs, Enums, and Traits.
For those who don't know, Traits are like a sort of "class interface" that can be automatically applied to things that have implementations for those traits, and conversion between, once that code is pulled in scope via `use`.
Rust doesn't have classes or inheritance, instead, it has more powerful tools, ones that aren't as limited.
Why is this being downvoted? Am I wrong about something? If so, please tell me, I'm still learning.
Ah. Maybe it's because I explained stuff that's basically newtypes using language that might make it seem they're different? Ugh. HN comments always make me so neurotic. But the content is usually more interesting than dev.to. I just wish they'd get rid of the downvote feature.
For what it's worth, I'm mildly experienced in Rust and your comment looks pretty much correct.
I'm recovering from a headache (and a little ketted out) so I might be missing something too, but in the spirit of trying to explain confusing downvotes, here's the only two potential nitpicks I can see:
1. newtypes are not really 'in addition' to structs, enums, etc. they are a particular type of struct with a fancy name.
2. Calling composition less powerful than inheritance could be seen as subjective and debatable. I mostly like composition over inheritance, but Rust for example has problems with up-casting of trait objects (https://github.com/rust-lang/rfcs/issues/2765) that inheritance/vtable based languages (e.g. C++) do not have.
So it's not a bad comment, and I suspect you mostly just got piled on due to human error/bias. Or maybe some poor soul got confused and thought you were trying to explain Rust to the poster above you (who may not need much explaining).
Don't take it personally, you seem to have a good grasp of the language. Please keep on learning :)
You know what would definitively prove whether it would? Just do it!
I'm so tired of these "rewrite in rust" articles that have no code behind them. Spend the time and write a replacement for curl, ship it, and people will start using it instead of curl. In some years time, you can write a paper showing how many vulns your replacement had vs. rust. curl continues to be written in C because it has someone actually doing the work to write and update it. A theoretical rust replacement does not exist because no one is doing the hard work of writing and maintaining it.
It's like LibreSSL vs OpenSSL. Did LibreSSL end up being more secure? At least we can find out instead of just guessing about whether removing crappy code from OpenSSL would be a good idea.
This is a tool issue and not a language issue. I think that if you do some thing in code that results in unintended behavior, then that's a bug that should be communicated to the developer during development.
A buffer over-run isn't a bug, its the symptom of a a bug in the arithmetic that computes how to access the buffer. The way to fix that is to communicate and address the bug during development, not to try to mitigate the symptom at run time.
I am a C programmer, and to me buffer over-runs are a rare class of bugs, and a class of bugs that are (at least on the heap, and often on the stack) trivial to find and fix with the tools i have.
Why are they so trivial to detect for you while they bedevil the rest of the software industry? Is it possible that there are many such bugs hiding in your code that have not been found, because your code has not been subjected to the amount of scrutiny that projects like cURL, Windows and Chrome have?
As someone who helps write an operating system, some areas of kernel code can be less subject to the usual C memory safety issues than most user code. This isn’t because kernel programmers are special, but because the kind of code that gets written is different. I rarely find myself allocating memory at all in kernel code, and if I don’t allocate memory, I’m less likely to overrun a buffer.
In other areas of kernel code, buffers common, but the data is completely opaque. You won’t find kernel code parsing a buffer written to a filesystem because there is nothing to parse. The buffer is literally just a pointer and a length.
That being said, I would love something like Rust for lifetime management and thread safety and for the occasional data structure.
(Large sections of Linux are indeed quite scary from a memory safety perspective. Anything related to /proc or /sys comes to mind.)
I don't find either of the Kernels you mention to be particularly unsafe, despite being written in "unsafe" languages. Can you point to better kernels written in Rust?
That being said, a kernel is a huge undertaking. There is nothing else with the scope of Linux. And substantial parts of writing a kernel involve dealing with architecture nastiness, and, in the absence of formal architecture models, no language will help much here. The Linux x86 low level code is a terrifying mess, and it’s also the best and most capable implementation I’m aware of. (I’m obviously biased.) A language like Rust would help only a tiny bit.
(Something like NMI handling on x86 is fundamentally memory unsafe. If you get nested NMIs, your stack gets clobbered. Thanks AMD. Linux has code, mostly in assembly, that detects and recovers. Good luck writing it in any memory safe language.)
I once skimmed seL4, and I would not use its x86 code for serious work in its current form.
> I am a C programmer, and to me buffer over-runs are a rare class of bugs, and a class of bugs that are (at least on the heap, and often on the stack) trivial to find and fix with the tools i have.
What does your testing setup look like? Does it include regular fuzzing and security audits? Buffer overruns are so common because normally your mental model of how the code should work assumes they don't happen, so you forget to test for their presence (or prove their absence, like Rust nudges you to).
That sounds like the opposite of the mindset I have when writing C. Keeping buffer limits in mind all the time, and having them communicated around the code/function calls and respected, is one of the most basic things.
I don't do fuzzing, because I leave string parsing to tools like re2c. I tried it in the past with my mail message parser written in C/re2c and it was not very helpful.
There are also other low-level languages besides C and Rust
I use Pascal, and I never have any buffer overruns in my code. If there were any, Pascal's automatic bound checking on array indices would raise an exception
The only issue is, should I keep the bound checking in the release builds for maximum safety, or disable them for maximum performance?
I tend to have tests on a lot of the time (see below about my test lib). As someone who has worked with C for a long time, I think my mental model is all about direct memory access, so it probably comes more natural to me.
How are they trivial? The issue with buffer overruns is that they're usually silent. If you have an array of pointers, and you overrun that array, you could end up assigning garbage to another pointer variable. Then when you deref that, if you're lucky it'll be outside the mapped memory addresses for that process and you crash. If you're unlucky, you read or write to a random location.
Basically the point is, it's very easy to end up in a situation where you know you have a bug but you're 2+ levels of indirection from the actual logic error. Those sorts of issues are always the biggest time sink.
I have a debug mode in my code base, where I wrap malloc, free, and realloc with debug versions that over allocate all allocations that are made, and put magic numbers before and after the memory blocks. These are periodically checked to make sure nothing has been overwritten that shouldn't be. You can find this code on my website, www.gamepipeline.org as part of the "forge" library.
The system tells me very precisely what has gone wrong with buffer over-runs, and it also make memory leaks and double frees trivial to find.
Visual studios debug mode does something similar with buffer overruns on the stack, but I tend not to put very many buffers on the stack so that much more rare as an issue.
If you want to go even more hardcore, windows has "gflags" that you can turn on to find overruns using memory protection.
LLVM also have the "Checked C" compiler that also finds these issues.
My own system is so good that, I haven't used gflags in a few years and I also haven't tested Checked C so I cant vouch for it, but there are loads of possibilities in this space that i hope to explore further in the future.
This testing-based approach is great at finding buffer overflows that occur within your test suite. But especially for code like curl that runs on untrusted data, you need a more adversarial mindset. Unless your tests cover every possible input, a clever attacker might always find input data that you didn't think to test.
These sound good, and I've used things like asan and ubsan which do a lot of the same thing. The issue is not everyone's running in a traditional environment where you have the conveniences of things like... an OS.
I sometimes write code for micro controllers, and I tend to wrap all system calls so that I can run the same code on my PC just to get access to better tools. On small hardware platforms its common that you are forced to use C because of the limited resources, so the options are limited.
I'm really happy to see the data behind the claim! I've been slowly desensitized to opinions masquerading as unsourced supporting graphs of dubious provenance. It's so simple, but kudos to the author for the transparency.
When Daniel wrote "C is not the primary reason for our past vulnerabilities", he may or may not have been right. But he sadly did not back that up with easily verifiable, refutable, data.
Data is like a ray of sunlight. Instead of arguing high-level opinions, let's argue the data