Comment by habibur

6 months ago

    5 million Rust LOC 
    One potential memory safety vulnerability found 
    Rust is 0.2 vuln per 1 MLOC.

    Compared to 
    C and C++ : 1,000 memory safety vulnerabilities per MLOC. 

Key take.

There are certain places on the internet where any mention of rewriting in Rust is met with scorn and ire. And while, like any technical decision, there are pros and cons, I cannot see why in the face of astounding evidence like this, you would completely dismiss it.

And I say this as someone who has never written a line of Rust in their life (some day I'll find the time).

  • In my experience, the loudest critics of Rust I have heard are actually seasoned C and C++ developers who are incredibly good at one or both languages, but know almost nothing outside it.

    On one hand, C++ is an incredibly complicated language that one can invest considerable amounts of time into. It also used to occupy a unique niche where you get tons of abstraction features yet as much blazing speed as you care to spend time optimising. Rust is encroaching on that niche.

    On the other hand, C is an incredibly simple language, which does not allow for convenient expressions of particular abstractions. If they hated C++ because it was too hard to follow. What the code is doing, they probably hate rust for the similar levels of abstraction affordances.

    When I hear the bad faith arguments from people who really should know better, what I hear is a group of scared developers who have been able to coast on their knowledge base for years or even decades, and are now feeling like their skill set is at risk of being unnecessary.

    It always seemed like an unproductive attitude to have in a knowledge-based industry like software development. I am also a C++ developer, but you bet I am learning Rust on the side, because I think it's a good idea to skate where the puck is headed. I also learned enough of Zig to be dangerous a few months ago because it was fun.

    Either way, I would suggest those developers reflect on the reason why they have this reflexive need to throw a wrench into any conversation mentioning rust. If their intention is to slow down adoption through hostile community sentiment, it's not working.

    • > what I hear is a group of scared developers who have been able to coast on their knowledge base for years or even decades

      That’s certainly not the case for C++. The C++ language has evolved quickly, with a release every three years or so. One could coast, but they would be writing outdated C++ that no newcomer likes. That is, the entire organization needs to also coast for this behavior to be viable.

      Instead I see most of the bad faith criticisms of Rust coming from aficionados of other languages in roughly the same space such as Zig or Nim, or occasionally Go. They whine because they think Zig or Nim should take the place of Rust.

      7 replies →

  • An earlier Google blog post from the same series (link in the first sentence) pointed out why: new code tend to have more vulnerabilities than established code. So it makes more sense to write new code in Rust than to rewrite old code in Rust. After all new features are still being added and new code needs to be written; it’s not like the codebase is done with features.

    • According to that blog post (https://security.googleblog.com/2024/09/eliminating-memory-s...), the vulnerability density for 5 year old code in Android is 7.4x lower than for new code. If Rust has a 5000 times lower vulnerability density, and if you imagine that 7.4x reduction to repeat itself every 5 years, you would have to "wait" (work on the code) for... about 21 years to get down to the same vulnerability density as new Rust code has. 21 years ago was 2004. Android (2008) didn't even exist yet.

      1 reply →

    • I also feel like this is good advice when making a language shift, or any _other_ shift, even a stylistic one.

      A lot of my coworkers get in this situation where, when a change in direction is made, they feel like we have to stuff the roadmap with work to rewrite everything. That work is... 0 value, in most cases, unless the decision we have made is intended to directly solve an issue in the existing code.

      Many times I find that if you just do new work in the new thing, you'll "naturally" prioritize rewriting at the right rate. When we do it that way, we end up replacing, rather than rewriting, those legacy systems, which avoids the pitfall of trying to reproduce prior behavior, down to the bugs it may have had.

    • >So it makes more sense to write new code in Rust than to rewrite old code in Rust.

      This is a general result regardless of what language you're talking about (unless you're really downgrading to assembly or something crazy). This of course presumes that the overall Rust (or other new language) situation is better than the existing one. It's not generally.

    • The blog post has a number of issues, including mixing C and C++. And Android C++ source code is often filled with C-style code, especially the older the code, and is not always that good in several aspects.

      As an example, from https://android.googlesource.com/device/generic/trusty/+/c3f...

      Many of the files in that commit have a lot of C-style code, yet are classified as C++. C and C++ are very different programming languages, and memory safety is arguably significantly easier to achieve in practice in C++ than in C, yet in the blog post, C++ is blamed for C-style code, and C and C++ are not differentiated.

      Compare and contrast with https://android.googlesource.com/device/generic/goldfish/+/d... . That source code file has much more modern C++. Though even then, it contains goto, and modern C++ code reviews would normally not accept goto in my experience. I do not understand what Google Android is doing when its developers are using goto. Could they not have used lambdas in those places where they are using goto? The mixture of std::string_view and goto, modern and yuck, is disconcerting.

      On a different topic, how much of the new Rust code is vendored dependencies? Is Fuchsia included?

      Maybe the real value for Google Android that Rust holds, is that it mostly prevents C-style code from being written. And Rust does not support goto, and while I think an argument could be made that goto is OK to include in a toolbox, its usage should be very, very, very, very rare. Why does somewhat modern Google Android C++ allow goto?

      I am not impressed by Google Android's C++ code quality. Are Google Android developers, independent of language, significantly below average?

      C++ does have baggage, cruft and issues. But having strange C++ code (like goto) and also blaming C++ for C-style code, does not help paint an honest and accurate image. And if Google Android's C++ code review process accepts goto willy-nilly, I do not consider Google Android to be at all credible on any subject related to code quality, memory safety and security in any programming language.

      12 replies →

  • > I cannot see why in the face of astounding evidence like this, you would completely dismiss it.

    We're decades into the global warming era. You simply can't make some people accept evidence if the conclusions from that evidence would be uncomfortable to them.

    If people don't take exploitability seriously, you can't make them. Well, unless you keep pwning them.

  • People are worried about half-assed[0] rewrites that break functionality and introduce exciting, new vulnerabilities due to improper implementation. And they aren't wrong to fear that, given the multiple issues we've seen in just the past week with Ubuntu's Rust overhaul.

    [0]: Or even whole-assed. Memory (un)safety is only one form of vulnerability.

    • They were half-assed in the sense that they trusted the old test suite, which turned out to be a mistake, as some edge-cases weren't covered. Hopefully they will be more rigorous going forward, but even then, these bugs were caught before being added to a stable release, so overall fine.

      I'm not sure if it is the best ROI to rewrite battle-tested tools in Rust, but it isn't like people are forced to do it. People have fun writing Rust, and want to work with it more, so that's the direction these projects take. And if you don't want to use these tools, the beautiful thing about Linux is that if you don't like the direction a distribution takes, you can always switch.

  • I think that it would be foolish for any software engineer to completely dismiss any technology. There is a time and place for any tool, and it is a job of a competent engineer to determine what the appropriate combination of these is that would solve a certain problem within specific constraints.

    That said, memory safety is one criterion out of many that could be used to make that decision. For a large number of software projects, memory safety simply isn't a major concern. Ease of use, iteration speed, developer familiarity, availability of specific libraries, and so on, are often equal or greater concerns than memory safety.

    So, sure, if you're writing a kernel, operating system, or a mission-critical piece of software, then Rust might be worth considering. Otherwise, you might be better served by other languages.

    • I dont so much dismiss the technology as the people who insist on rewriting everything in rust.

      Rust seems to attract a certain mindset of mediocre programmers who yell "security" to shove their poorly written slower code down our throats.

      Most of them seem to be former web developers who bring all their npm drama to stable C foundations

      2 replies →

  • > I cannot see why in the face of astounding evidence like this, you would completely dismiss it.

    Because it's not a silver bullet. That safety comes at a cost; Rust is much more difficult to learn than C or Zig and the compilation time for code with equivalent semantics is an order of magnitude greater. It has also added a great deal of toolchain complexity to projects like the Linux kernel.

    People have decided that the pros outweigh the cons in those particular cases, but those cons exist nonetheless.

    • Rust is more difficult to learn the basics of than C, but I'm not sure it's more difficult to learn to write memory-safe code in Rust than in C. It's also not clear to me it's that much harder to learn Rust than it is to learn how to write equivalently-high-level code in C++ _unless you end up in one of the areas where Rust is really hard_. But a lot of systems code doesn't end up in those areas. Some does, and then you have to go fishing for a crate that does things for you. C++ just has a lot of corners you can get sucked into, and the legacy mix of multiple generations of C++ coding styles / OO stuff makes for some really tangled messes out there.

      (fwiw, I teach undergrad systems programming in C, I use Python at the startup, and I use a mix of C/C++/Rust in research.)

      I would personally much prefer to use Rust for code exposed to external untrusted input than to use C. I have substantially more confidence that I would not add exploitable bugs given the same time budget.

      10 replies →

    • Is it harder to learn than C? For sure it is a bit harder to get started. But is it also harder to learn than writing proper C(++?) with the same amount of quality in terms of lack of bugs ?

      8 replies →

    • > Because it's not a silver bullet.

      It does look like a silver bullet, actually. In the context of software engineering, "silver bullet" inevitably leads to Fred Brooks:

      '"No Silver Bullet—Essence and Accident in Software Engineering" is a widely discussed paper on software engineering written by Turing Award winner Fred Brooks in 1986. Brooks argues that "there is no single development, in either technology or management technique, which by itself promises even one order of magnitude [tenfold] improvement within a decade in productivity, in reliability, in simplicity."

      Reducing memory-safety vulnerabilities by 5000x compared to the prior approach is not just a silver bullet, it's an arsenal of silver bullets.

      > the compilation time for code with equivalent semantics is an order of magnitude greater

      The time it takes to write and run the comprehensive tests for C and Zig code to demonstrate anything even approximately in the ballpark of what Rust gives you for free is a multiple orders of magnitude greater than whatever time you spent waiting for the Rust compiler. Why care about the time it takes to compile trivially incorrect code, rather than caring about the total time it takes to produce reliable software, which is demonstrably lower for memory-safe languages like Rust?*

      3 replies →

    • To me, those sound like meaningful pros and cons, not a reason to completely dismiss it.

  • >"There are certain places on the internet where any mention of rewriting in Rust is met with scorn and ire."

    Nah. For me it induces vomit. Any time the vulnerability is mentioned a horde will arrive promptly and sing "rewrite the ... " in Rust.

    For fuck's sake. We got it. We know it is mostly memory safe with bunch of other protections baked in. So go and rewrite it and then try to sell it to your customer and have them pay for this job. If you succeed - congrats, good for you and for the "victims". If not - stop nagging people who have other things to worry about.

  • One who has tried the language and hates it can completely dismiss it. Memory issues can be fixed in ways that don't involve rewriting millions of lines of code and the ensuing chaos, feature degradation, retraining, etc. that goes with it.

  • It's one class of bugs. This is not enough information to make a technical decision. Logic bugs still exist. It's not clear if these are easier or harder to create in Rust. There is some existing evidence to suggest that object oriented programs make it easier to create logical errors and emergent bugs.

    So, that's why I completely dismiss it, it fraudulently attempts to champion Rust as an obvious replacement of anything. For those who think this has something to do with Rust specifically, no, we've held these reservations for promised replacement languages for decades now. There is no evidence Rust's borrow checker alone has overcome enough of the problems of any previous example.

    A short criticism of Rust is, for a supposed systems language replacement, they let far too many features and first party magic (cargo) into the language.

    • 70% of bugs in a large mature c++ code base come from memory safety bugs. Yes it's not the only type of bug, but it sure is the majority. Other types of logic bugs are also easier to avoid in rust because it's type system is quite powerful. Rust enums make it easier to associate state with specific states, option types actually force you to check if they are valid, result types force you to check for errors, etc. Anyone who's actually migrated a code base from c++ to rust should be able to attest to the benefits.

      4 replies →

  • Generally speaking, the purpose of a program is not to minimize the number of memory safety bugs. All other things being equal, yes, having fewer memory safety bugs is better than having more. But perhaps you're trading legible bugs for illegible bugs? The rust implementation is most likely going to be more complex than the c implementation (which is fair since it almost eliminated a whole class of bugs), and in that complexity there is extra room for non-memory safety related bugs.

    There's probably also 500x more people who know c to a given level then know rust to a given level.

    If we have an analyzer that can find memory safety bugs in C, we could also just put that in the CI pipeline, or as a pre-submit hook before you're allowed to add code to a code base.

    • This idea that if Rust doesn't have all those memory safety bugs it must somehow have loads of other bugs we haven't discovered reminds me of Americans insisting that countries which don't have their lousy gun safety problems must have the same effects by some other means they haven't detected - Like, OK England doesn't have lots of gun murders like America, but surely loads of English people are just dropping dead because someone threw a yoghurt at them, or used harsh language, and we just missed them off our statistics ?

      No man, it is possible to just do better, and this is an example of just doing better. The Rust is just better software. We can and should learn from this sort of thing, not insist that better is impossible and the evidence suggesting otherwise must be a mirage.

      2 replies →

    • You're not fully understanding the issue with memory safety. When you write C or C++, you're promising that you won't violate memory safety at all. That's just a basic requirement of what it means to write in those languages.

      The graph about reverted code also addresses the "illegible bugs" argument.

      As for an analyzer, that's what ASAN is. I hope I don't need to explain why that's not a universal solution (even though everyone should be using it).

      11 replies →

    • Chances are, a Rust implementation of certain things may be simpler than C implementation. C is a low-level language, so you have to do more housekeeping, and express things obliquely, via implementation, vs expressing things more declaratively in Rust.

      Being simpler is not a given though.

      "Knowing C" as being able to read and understand what's happening is quite separate from "knowing C" as being able to write it competently. Same thing with Rust: an algorithm written in rust is far from impenetrable for a non-expert, and even someone who sees Rust the first time but has enough experience with other languages.

    • The idea that people occasionally throw around that C is more 'simple' and less 'complex' than C++ or Rust and therefore it leads to more maintainable or easy to understand code is, IMO, completely bogus.

      C is not simple, it is inept. There are so, so many bargain-bin features and capabilities that it just cannot do that it ends up creating much MORE complex code, not less complex code.

      I mean, just the pretense that simple tool = simple engineering isn't necessarily true. Building a home using an excavator and drills is fairly straight forward. You know what's complicated? Trying to build a home using only a screwdriver. Yeah. Good luck with that, you're gonna have to come up with some truly insane processes to make that work. Despite a screwdriver being so much more simple than an excavator.

      Trivial example: you want to build a container that can hold data of different types and perform generic operations on them.

      C++ and Rust? Easy. Templates and generics. C? Up until a few years ago, your options were: 1. copy and paste (awful) or 2. use void * (also awful).

      Copy and paste means your implementations will diverge and you just artificially multiplied your maintenance burden and complexity. And void pointer completely throws away any semblance of type safety, forces you to write stupid code that's way more complex than it needs to be, and, to top it off, is horrible for performance!

      That's just one example, but there's so, so many when you look around C++ or Rust enough. And these are not rare things, to me. To me, these are everyday coding problems.

      Anonymous functions? There's another one. Encapsulation? Just making not literally every piece of data universally mutable? Not possible in C. Trivial in C++ and Rust, and it makes your programs SO much easier to reason about.

      9 replies →

To be honest I feel like "this code is easier to review and less likely to require rollbacks" is even more of a valuable take from this article, just in terms of "hey, don't you like it when things don't have to be rolled back?"

Security issues are like bad etc too, just we've heard the security spiel so many times at this point. I just think it's nicer to write most stuff in Rust.

  • Yes, Rust's strictness makes it a lot more maintainable. It is so much more common that changing the one thing you wanted to change results in a compiler error at every single other site you need to change, without having to look at other areas of the codebase at all, and all the tests pass on the first try.

Rust is truly a marvel of engineering. A breakthrough. Such a thing is so very rare in computer science.

  • I don't know much about how it got started. I'm curious how much of Rust's capabilities depend upon recent CS breakthroughs. Could we have made Rust in 1990?

    The compiler is also relatively slow. Would Rust have been worth working with on 30+ year old hardware?

    • > Could we have made Rust in 1990?

      No. Only massively oversimplifying, Rust could be described as a bunch of ideas pioneered among functional languages coming back to C++, the same way Java was a bunch of ideas from Lisp coming back to C. There is very little that's truly new in Rust, it's just mixing a bunch of features that were not often together before.

      > The compiler is also relatively slow. Would Rust have been worth working with on 30+ year old hardware?

      What makes Rust slow to compile is largely independent of what makes it unique. A lot of text has been written about this, but the again massively oversimplified version is that had the designers cared about compile times when the language was being designed and the compiler written, you could have something that's very similar to Rust but also very fast to compile.

    • > The compiler is also relatively slow. Would Rust have been worth working with on 30+ year old hardware?

      As I understand it, a lot of the slowness of the rust compiler comes about from llvm. And how rust and llvm interoperate. Rustc creates and sends gigabytes of stuff to llvm - which passes all of that to its optimizer. If you skip all that work - for example by running cargo check - the compiler is an order of magnitude faster.

      If rust were invented in the 90s, it wouldn’t have used llvm. Rust could still have been implemented, and we’d probably have a much faster compiler as a result. But it would have missed out on all the benefits of llvm too. It would have needed its own backend to be written - which would have been more work. And the compiler probably wouldn’t have been as good at low level optimisations. And it probably wouldn’t have out of the box support for so many target platforms. At least, not from day 1.

      4 replies →

    • I think the answer is probably that Rust was possible in the 1980s and 1990s, but such a thing just wasn't practical.

      Rust is notoriously compiler-intensive. That wouldn't have been tolerated in the early PC era. When you needed fast compilers that "worked on my machine" and should work on yours. Ship it.

      1 reply →

    • > Could we have made Rust in 1990?

      We did, it was called OCaml. If we'd had any sense we'd've rewritten all our systems code in it. But since C had bigger numbers on microbenchmarks, no-one cared.

      10 replies →

Yeah, I am blown away. Assuming that these stats are true/verifiable, this spells real doom for C++. What is the point of C++ in 2025 except to maintain a large, existing source code base? Else, you should be doing everything that you used to do in C++ in Rust.

  • > What is the point of C++ in 2025 except to maintain a large, existing source code base?

    Half of useful things to do are impossible or plain cumbersome to write in rust given the semantics and constraints of the borrow checker. Try to write self referential structures in rust and you'll have a more nuanced opinion.

    • That’s entirely the point, though. Rust compiler is of the opinion that recursive data types are hard and I don’t think it can be reasonably argued that this opinion is incorrect.

      Feel free to use unsafe {} when you need it, though.

    • I’ve written self-referential structures in Rust with the ouroboros and self_cell crates. It was fine, and I got way more guarantees I got it right compared to C++.

  • That's also a reason why Google is researching with Carbon, they have for sure a hunger to migrate away from C++.

Note that N=1 for the memory safety vulnerabilities they had with Rust, so the error of the estimated average number of vulnerabilities per LOC is quite large.

  • Yes. I would make a guess of 10 or less memory-safety vulnerabilities per MLOC, which is still a hundredfold reduction.

    • Your best guess is that the true rate is 20x higher than the observed rate? This seems unlikely to me given the number of samples (outside of systematic biases towards certain types of memory safety bugs that probably apply to C++ code too). 10 per hundred MLOC is closer to what I would have guessed too, but that is because I've historically been very conservative with my assumptions about the memory unsafety rate per unsafe LOC being similar to that of C++. The evidence here suggests that the true rate is probably much lower than that.

      1 reply →

Those are orange vs apple, just like the rate of rollbacks

They compare something new, which rewrite existing stuff (not only but still) with some decades-years-old cruft

In they new code, they know what they want

They can also start with state-of-the-art unit testing that may not exist in the early 2000

So .. yeah, those numbers ..

That rust is saner than c++ is a given anyway :)

Isn't that a lot though, that means 1 memory safety vulnerability per 1000 lines of code, that seems hard to believe.

  • Take a look at the examples in this post: https://www.microsoft.com/en-us/msrc/blog/2019/07/we-need-a-...

    Large C++ codebases have the same problems that large codebases have in any language: too many abstractions, inconsistent ways of doing things, layers of legacy. It comes with the job. The difference is that in C/C++, hard-to-read code also means hard-to-guess pointer lifetimes.

    • If the C++ code I worked on looked like that[1] and was actually C with classes, then I’d be switching to Rust too. For Google and Microsoft it probably makes sense to rewrite Windows and Android in Rust. They have huge amounts of legacy code and everybody’s attacking them.

      It doesn’t follow that anyone else, or the majority has to follow then. But that’s predictably exactly what veteran rustafarians are arguing in many comments in this thread.

      [1] Pointers getting passed all over the place, direct indexing into arrays or pointers, C-style casts, static casts. That (PVOID)(UINT_PTR) with offsetting and then copying is ridiculous.

I fear Androids problems with Google as steward has other significant problems than memory safety.

To a degree that users might want to even exploit such flaws to unlock their phones.

Aside from that. Sure, the constraints of Rust do solve these kinds of problems.

They found a memory safety bug in their Rust code and assumed it was the only memory safety bug in their Rust codebase. And then they compared it to the historical average in C++ code that's been around for almost two decades in production. I can't be the only one here who sees how biased this comparison is right?

  • Rather, they found one memory safety bug in their Rust codebase, and measured it against the legions of memory safety bugs they found in their C++ codebase. In neither case are they measuring against bugs not found, so no, it's not biased.

    • Except it's not an apples-to-apples comparison. The C++ code has been around a lot longer, and a lot of it was written with older versions of C++ which didn't have modern safety features. I'm sure there is a bunch of new/delete in their codebase still. And I'm sure they're actively looking for memory safety issues in C++, and probably not so hard (if at all) with Rust.

      8 replies →

  • If you want something more comparable, they estimate that only 5% of their Rust code is within unsafe blocks. That makes only 5% of the code with potential for memory safety issues: that's already a 20x improvement. Let's make it 10x because unsafe blocks tend to be trickier, but you still get a lot of Rust guarantees.

    The thing is with Rust, you know where to look for memory safety issues: the unsafe blocks. C and C++? GLHF that's your whole codebase. As they mentioned, you don't opt-out of all of Rust guarantees by going the unsafe route. Of course you can ditch them, but that'll be hugely visible during code review. Overall, you can be much more confident saying "yup there's no bug there" in Rust than in C or C++.

  • Even if they are off by a factor of 100 it's a huge win and the point stands.

    It's fair to point this out and worth the mention. Still, I'd like to think that the engineers behind this can at least gauge the benefit of this endeavor with some accuracy despite the discrepancy in available data, and stating the data that is available only makes sense.

  • and they found 1000 memory safety bugs and assumed it was the only 1000 memory safety bugs in that code which have been in production for 2 decades. How naive can they be?

Further up they refer to Android C/C++ code, not C/C++ in general:

"We adopted Rust for its security and are seeing a 1000x reduction in memory safety vulnerability density compared to Android’s C and C++ code."

Which means they had a pretty poor code base. If they had spent more time on engineering and less time on features that are canceled after 12 months anyway, they could have written better C/C++.

  • I peruse Android system code at work and their C++ code base is not designed for safety. It’s just typical C++ code as any large company would write it.

    And for a large juicy target like Android, that won’t be good enough to stay ahead of the attackers long term.

    Of course, tools like Fil-C or hardware-based security might make Rust vs. C or C++ moot.

    Edit: your comment makes a good point. Shame that trigger-happy (c)rustaceans are downvoting everything in sight which is not praising this PR piece disguised as a technical blogpost.

    • While crashing is better than exploitable behavior, catching bugs at compile time is even better. Neither hardware based strategies nor filc actually find bugs at compile time. Also the conversation with respect to security isn't about migrating old code, but what to use for new code that you write.

      I will note that developers also feel more productive in rust. That's why they migrate existing things over to it even when it may not be beneficial for security.