15 ms·
How memory safety CVEs differ between Rust and C/C++
- ashish296 4mo ago[flagged]
- chilljinx 4mo agoUnsafe is not necessary to trigger UB in case no_std is used. Nor if one of the soundness holes in the Rust programming language itself is encountered. Nor if there is UB in one of the libraries used as a dependency by the library you are using. Nor if there is UB in the Rust standard library. Which has happened many times, since the Rust standard library is full of unsafe. Rust also requires libraries to be safe regarding unsafe, no matter what kind of insane input that is given to the library and that would otherwise potentially be security issues. Which is too difficult for many library authors. And unsafe in Rust is so difficult that many library authors throw their hands up, use Miri, and hope for the best. Even though Miri, all respect to it, has bugs, probability-based testing and other limitations and issues. UB in both user library and standard library: https://materialize.com/blog/rust-concurrency-bug-unbounded-channels/ https://materialize.com/blog/rust-concurrency-bug-unbounded-...
- kllrnohj 4mo ago> Nor if one of the soundness holes in the Rust programming language itself is encountered. imo one of those soundness holes is caused directly from trying to prevent UB - integer overflows. It is inconsistent in Rust what happens in that scenario depending on compiler flags, which basically just makes it UB for any given piece of code. And, unfortunately, default release mode behavior is unsafe.
- chilljinx 4mo agoWhich definition of UB are you using regarding that? Behavior changing based on configuration does not seem like UB, at least if none of the configurations allow for UB.
- afdbcreid 4mo agoYou seem to have been misinformed. Rust panics on overflow in debug mode (or always if you toggle a compiler flag), and has a guaranteed wrap-around in release mode. In no case there is UB.
- Groxx 4mo agoSupporting evidence for this: https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-overflow https://doc.rust-lang.org/book/ch03-02-data-types.html#integ...
- kllrnohj 4mo agoNo, that's exactly what I'm aware of, and is exactly the wrong behavior I'm talking about. "Sometimes crashes, sometimes two's compliment" are extremely different behaviors, and not meaningfully different from just saying it's UB. It should always panic, with no way to disable it. The wrap around in release mode is simply bad behavior. It can't be relied upon (because it panics in debug), and it's not useful behavior for nearly anyone's logic (wrap around almost never is logically correct behavior) It lets Rust claim to be UB free without delivering the actual value of being UB free. You still can't rely on a given behavior because it doesn't have one behavior, it has two, and the two behaviors are wildly incompatible with each other.
- steveklabnik 4mo ago> and not meaningfully different from just saying it's UB. It is extremely meaningfully different, because the range of options of what can happen is bounded in one case (either two's compliment wrapping, or panic) and unbounded in the other case (literally anything is allowed to happen, including time travel). This is "implementation defined behavior" in C and C++'s terms, not "undefined behavior."
- Dylan16807 4mo agoIf you want guaranteed wrapping or panic you can choose one and then rely on it just fine. The default behavior helps you avoid wrapping without permanently bogging down your performance. It makes sense as an option.
- slopinthebag 4mo ago> The fix for this bug is included in Rust 1.87.0 Am I missing something?
- afdbcreid 4mo ago> Unsafe is not necessary to trigger UB in case no_std is used I have no idea what are you talking about, no_std is just completely irrelevant here. > Nor if one of the soundness holes in the Rust programming language itself is encountered Have you actually examined those soundness holes? It is basically impossible to hit them without writing code which is meant to hit them. And this is also noted in a footnote. > Nor if there is UB in one of the libraries used as a dependency by the library you are using If we treat a Rust program globally, this is kinda true. A more true statement will be that UB cannot happen without unsafe code somewhere, including in dependencies (and the original statement can be interpreted as saying that). But the true power of unsafe is that it's local. If you've reviewed a library and its unsafe is sound, you can ignore it for the rest of the calculation. And of course, the more people review a library the more likely it is that it is sound. > Which has happened many times, since the Rust standard library is full of unsafe And here again the post's point stands: many CVEs in std are artificial, you can't exploit them without writing a program that is meant to be exploited. Such thing will never be a CVE in C/C++'s std. > Rust also requires libraries to be safe regarding unsafe, no matter what kind of insane input that is given to the library and that would otherwise potentially be security issues. Which is too difficult for many library authors. That is true, that is in fact the post's point: that if they fail this, a CVE will be filled, even if exploitation is just not possible realistically. But there is a very simple solution for library authors: don't write unsafe code! You don't need to, the vast majority of times. And if you do not have the knowledge (which indeed is more complicated than in C/C++) how to not have an unsound API, then you just should not write unsafe code.
- Groxx 4mo agoI'm caught somewhere between interpreting this as "C is all we need. git gud" and "rust hurt me and I'm still mad" and I'm struggling to see any other option. It's an unfocused rant that seems keyed off "rust" and little else. In broad strokes it's correct, this stuff happens and it's hard to be correct all the time. But are you trying to make a point? Or just ranting? Also that linked issue was considered a CVE and is fixed (as the article says).
- chilljinx 4mo ago[flagged]
- fluffybucktsnek 4mo agoNo, they are asking for clarification.
- IcyWindows 4mo agoI see his reply as "people say Rust is safe, but Rust just pushes it under a rug and pretends it's safe when it's still all there - just in a dependency"
- sunshowers 4mo agoIf you are interested in a more nuanced take on what makes unsafe Rust both valuable and difficult, check out my blog post on the Oxide blog: https://oxide.computer/blog/iddqd-unsafe https://oxide.computer/blog/iddqd-unsafe I directly tackle the concerns you mentioned, and as a followup I'm actually working on formally verifying the library as well (I've had some success and will publish an update regarding this).
- reallyinchaos 4mo ago[flagged]
- sunshowers 4mo agoI'm a huge fan of Rust! I like to think my writing makes the Rust community better more than it annoys people :)
- reallyinchaos 4mo ago[dead]
- aapoalas 4mo agoOoh, cooll to hear you got some uptake on the call for formal methods help! Or did you end up figuring it out on your own? Either way, looking forward to the followup!
- sunshowers 4mo agoMostly chatted with some people and figured it out with their help.
- sunshowers 4mo agoUpdated https://oxide.computer/blog/iddqd-unsafe#what-about-formal-methods https://oxide.computer/blog/iddqd-unsafe#what-about-formal-m... with some notes.
- jurschreuder 4mo agoJust want to remind everyone that only 1% of vulnerabilities are memory related in the average Joe's code. And only 20% of memory related bugs are use-after-free which the borrow checker fighting is for. And 100% of the use-after-free exploits were to gain admin rights on an already hacked Windows (all windows) computer. So for the vast majority of people the borrow checker adds nothing. The vast majority of memory safety bugs (extreme pro level, super hard to exploit, only worth it in massively adopted evil outer world facing software) can be fixed by using C++26 with array bounds checking and forced initialisation. These last two things that Rust forces catch 70-80% of the memory problems the borrow checker only 20-30% only use-after-free. Most problems by far for normal developers are supply chain attacks, exposing api keys, remote code execution, wrong input validation, wrong auth-flow. You're reading the CVEs of sudo and ssh and think your code will be hacked like that. PHP is memory safe and still many people hack wordpress plugins.
- slopinthebag 4mo agoAny sources for these numbers?
- lawn 4mo ago90℅ of all statistics is made up.
- Sohcahtoa82 4mo agohttps://www.youtube.com/watch?v=r7l0Rq9E8MY&t=2s https://www.youtube.com/watch?v=r7l0Rq9E8MY&t=2s
- jurschreuder 4mo agoYes all of them have sources. Look for example top 500 CVEs of this year (after many fixes in C++, not right when the 70% memory issues in Chrome came out). Look at top 10 CVE github 2025 (zero memory related does not make it). Look at that sudo-rs was not allowed in Ubuntu because it's not as safe (way worst track record) than the C version, almost all is input sanitation. Look at wordpress plugins hacks, all PHP all memory safe language. Compare that to HAProxy and Nginx (C). Etc.
- shevy-java 4mo agoC and C++ are kind of losing out to Rust right now. Take ladybird (last month blog; not that ladybird stands for all projects out there, of course; it is just an example): https://ladybird.org/newsletter/2026-05-31/ https://ladybird.org/newsletter/2026-05-31/ "The HTML parser is now written in Rust" "The Rust parser is also about 10% faster than the C++ version it replaced," I am not saying this is a systematic analysis by far, but Rust is pushing into domains where C and C++ dominated in the past. And that seems to be a real push. To me it looks as if both C and C++ are standing to lose some ground in the next few years, directly to Rust. Perhaps even via snowball effect.
- deleted 4mo ago[deleted]
- ghosty141 4mo ago> but Rust is pushing into domains where C and C++ dominated in the past. I think it's also a big sign that the linux kernel adopted rust and not c++. (only for small parts but still)
- tialaramex 4mo agoA not inconsiderable part of why is that Rust for Linux did the work. When C++ people say they think there should be C++ in Linux, their proposal usually begins by proposing that it "should" be possible to just compile Linux as C++ software. This doesn't work because C isn't just "C++ but old", and they rapidly lose interest. Which of course also feeds into Linus' semi-fair claim that not allowing C++ keeps out the low effort wannabes who would plague such a project. This makes C++ developers very angry, but part of the reason why is that it's true, C++ does attract these people. The Rust for Linux people wrote a lot of code, a lot of documentation, they did Q&As, they worked very hard to actually deliver the idea to the kernel community, it's a totally different approach, it's a lot more work but some people thought it was worth the work.
- cesarb 4mo ago> their proposal usually begins by proposing that it "should" be possible to just compile Linux as C++ software That has already been done in the past. Quoting the FAQ: "[...] the kernel was once modified to be compiled under g++. That lasted for a few revisions. People complained about the performance drop. It turned out that compiling a piece of C code with g++ would give you worse code. It shouldn't have made a difference, but it did. Been there, done that."
- cesaref 4mo agoIs it only me that would have expected curl_getenv() to have an assert that it's argument isn't NULL? I know this doesn't stop runtime problems in release builds, but i'd have thought this sort of simple precondition check would help users find problems in their library useage. It's not going to stop you passing a non-terminated string, or other such invalid input though, which is I guess more the point, that it's totally possible in C to produce good looking but actually invalid arguments that can't be spotted at runtime without UB (out of bounds access etc). Edit: Actually thinking about this more, I guess the problem is that you are likely linking against a release library implementation, so it's not possible to add a precondition without introducing a runtime overhead, which is probably more likely what we are talking about with this case.
- hathawsh 4mo agoIf I were doing a code review, I would probably accept the code either with or without the assertion. The context of curl_getenv() makes it clear that null is not acceptable. If the author of curl_getenv() had evidence that callers are frequently breaking the contract by passing null, then perhaps the assertion would help shed some light on violators. Otherwise, I would expect everyone to play by the rules, making the assertion unnecessary.
- favorited 4mo agoIt's also just a wrapper around getenv that provides consistent behavior across platforms, and passing a NULL name to the POSIX getenv function is UB.
- vintagedave 4mo agoThat is exactly why you have a precondition or assertion. If everyone expects specific behavior - ie it’s in the contract - you require that contract.
- hathawsh 4mo agoYes, but null pointers are so pervasive in C code that we really can't afford to put assertions everywhere. It's often better to let the app crash on violations.
- fweimer 4mo agoI'm not convinced this is true. Otherwise, it does not bode well for Rust code because any type safety glitch will be considered a vulnerability. This would be really challenging for Rust developers because it goes beyond unsafe Rust code. You can easily have unexpected panics because your types do not enforce invariants as you expect. If a library has such a bug, is this a denial-of-service vulnerability in the library? Rather than dealing in absolutes, I would say that it's impossible to tell in isolation. If applications do not misuse the library in ways that triggers the panic, probably not, and treating this as a vulnerability just results in pointless noise. Determining the impact of library bugs can be really hard. For example, some functionality might be so broken that it's simply impossible to use correctly, so a buffer overflow on top does not make a difference. Or a buffer overflow vulnerability triggers consistently during system boot, so that you never get to the login prompt. These can hardly be considered vulnerabilities. On the other hand, we have clear buffer management bugs, where we must expect that there is application code out there which specifies tight buffer bounds and requires that the library stays within that buffer. (Rust should help here, at least out-of-bounds accesses should turn into panics.) But most bugs are unfortunately somewhere in the middle. Tools like Debian Code Search can provide some evidence. But in the end, it's more subjective than I'd like it to be. On the extreme end, we have compiler soundness bugs. I'm a bit of worried that I'm hitting any of those when I'm tweaking the types until the compiler no longer complains. Beyond the basics, I really don't have a grasp of Rust's type system rules. But I suspect they very difficult to hit by accident, and even if I do, the code must be miscompiled in meaningful, but difficult-to-notice way. All that seems rather unlikely, which is why these bugs aren't treated as vulnerabilities. I really think we need some corrective factor (such as potential implication impact) when determining whether toolchain bugs are vulnerabilities.
- afdbcreid 4mo agoYou said > I'm not convinced this is true. But it is. It is true that Rust libraries could take this position of "any API misuse causing vulnerability is a CVE" more to the extreme, currently it is applied to memory safety but it could be applied to panics as well. However it is still true that pretty much all Rust libraries treat API misuses that cause UB as a CVE, and pretty much no C/C++ library does that, and that inflates the number of Rust CVEs. > On the extreme end, we have compiler soundness bugs. I'm a bit of worried that I'm hitting any of those when I'm tweaking the types until the compiler no longer complains. Beyond the basics, I really don't have a grasp of Rust's type system rules. But I suspect they very difficult to hit by accident, and even if I do, the code must be miscompiled in meaningful, but difficult-to-notice way. All that seems rather unlikely, which is why these bugs aren't treated as vulnerabilities. Rest assured that you are much more likely to hit a miscompilation in your compiler's backend, and that it is much harder to detect.
- john_strinlai 4mo ago>Because sometimes I see people online who compare the number of CVEs in Rust and C/C++ software, [...] a rule of thumb i follow is that the second someone starts comparing or talking about the number of CVEs, i just ignore whatever they say next. its hard to think of a more useless metric than "number of CVEs", especially now. (edit: the people disagreeing are encouraged to share how you use "number of CVEs" to inform your decision making)
- kkishahva 4mo ago[flagged]
- mswphd 4mo agointeresting links > Others think someone from the Rust (programming language, not video game) development community was responsible due to how critical René has been of that project, but *those claims are entirely unsubstantiated* huh > The guy that tried to SWAT me was extremely enthused about Rust: never shut up about it. hm. the guy was also ostensibly a male. should we ban all men from HN? maybe they should be fired and shunned and cast out of society.
- dtornabene 4mo agoyeah this is absurd and a brand new account pushing it too.
- kwveddlsjggej 4mo agoThey've been registering new accounts to bring this up in Rust-related threads for months. Their tone has escalated from concern to vitriol, and this is the first I'm seeing open calls for violence. Commenter, whoever you are, I sincerely hope you have people in your life to talk to and that you are doing okay. I am genuinely concerned.
- bawolff 4mo agoI'm not sure i think those situations are comparable. If a rust func is taking an Option<t>, its essentially advertising that it can handle None values. That feels quite a bit different from giving a c function a null pointer and having it freak out.
- eptcyka 4mo agoYe, sure, but Rust won’t compile a `foo(std::ptr::null())`, if the function is defined as `fn foo(b: &Baz)`. C doesn’t get that luxury. That is the point of the article.
- f33d5173 4mo ago$ gcc -Wall -Werror -x c - << EOF void f(int x[static 1]){}int main(){f(0);} EOF <stdin>:1:37: error: null passed to a callee that requires a non-null argument [-Werror,-Wnonnull] 1 | void f(int x[static 1]){}int main(){f(0);} | ^ ~ <stdin>:1:12: note: callee declares array parameter as static here 1 | void f(int x[static 1]){}int main(){f(0);} | ^~~~~~~~~~~ 1 error generated. It can be done, though it usually isn't.
- saghm 4mo agoCan you do that with a dynamic array? If not, it's pretty severely limited (unless you mean that literally forbidding dynamic memory is usually not done, which I guess it's true outside of some embedded code but not a particularly meaningful statement).
- f33d5173 4mo agoThe syntax is rather confusing. This is not an array of length 1, but rather a pointer which points to a memory segment which is at least 1 integer long. In other words, any array of any length (>=1) would be a valid argument to this function. "static" here means "don't do the normal thing where you totally ignore the length of an array argument to a function (which is, like usual, really just a pointer)". "static" was chosen because the keyword was available rather than because it was a particularly descriptive name.
- ankitpsaraogi 4mo ago[flagged]
- bitbasher 4mo agoMemory safety is a concern, but there are many solutions that don't include Rust. Rust is certainly one solution, though. However, Rust seems to trade memory safety vulnerabilities for supply chain risk.
- anuramat 4mo ago> supply chain risk how is rust special in this regard?
- galangalalgol 4mo agoIn languages that don't have a culture of deep dependency trees managed with good tooling, supply chain attacks are perceived as being more difficult or rarer. That may or may not be true. But it is a concern in any case. Rust could have had namespaces to decrease namesquatting. The "no deps younger than N days" thing will help some. Those with this perception would prefer a large stdlib that is well vetted or that they can pretend is well vetted. In practice, if you don't use tokio you are likely not using anything that isn't written by a well known member of the rust community. Tokio brings in a lot... The real fix comes in two flavors, pay to write everything yourself and test it well. Or limit what a bad dependency can do. The latter is difficult in every mainstream language. Austral had a good answer for it, but seems to be dead.
- anuramat 4mo ago> austral thanks, can't believe the idea isn't more mainstream -- I've never thought dependency safety could be a thing
- galangalalgol 4mo agoIn rust if you can verify a dependency is no_std with no unsafe code and that all of it's dependencies are the same, then it can't get to libc or the kernel syscalls. So any privilege it works with is something you passed it. But that amounts to writing everything yourself in practice.
- thegrim33 4mo agoReally annoying when people take 50 year old C code and modern C++ code and just drop them into the same bucket and refer to them as if they're the same thing. The CURL example they give has multiple modern C++ solutions that accomplish the same thing without UB.
- afdbcreid 4mo agoThis doesn't matter to the post, because it is about culture, not about code. And there are plenty of ways to cause UB with modern C++ idioms.
- okanat 4mo agoI'm a / used to be a C++ programmer for 10 years. I've been lucky enough to work in a company that aims to adopt Rust. I have been working on Rust projects in the embedded space that runs on real-world devices right now for 3.5 years. Slowly but surely, not going into "rewrite every single thing now in Rust" but one component at a time when the project justifies it. So, tell me what compiler option disables non-modern C++ code? Is there one that enforces that every single variable including stack ones work like unique_ptrs without paying the price? How about safety checks in std; is there an opt-out style safety checks where I can ensure that I'm not adding random things to a map with the [] operator, the library checks size of vector when I access elements in non-performance-critical code, anybody can use iterators safely without being able to write code that can change contents of a container? How about std::thread? Is there an enforcement switch that I can only pass in things that work exactly like trivially_constructible<T>s, unique_ptr<T>s or shared_ptr<mutex<T>>s and nothing else? Is there a compiler switch that completely goes against https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f42-return-a-t-to-indicate-a-position-only https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines... and ensures that no unchecked pointer access happens without explicit approval from the developer? If those all exist, is there a movement to port many of the core building block libraries to that special compiler including std without being afraid of breaking ABI? Those are all what Rust developers (who were or still are quite advanced C++ devs, btw, not people who are afraid of using raw ptrs) get freely from the Rust compiler. A lot of "modern" C++ code still contains and, by design, cannot avoid creating unintended and unlimited UB.
- deleted 4mo ago[deleted]
- Decabytes 4mo agoBjarne Stroustrup was recently interviewed by Ryan Peterman^1 1. https://youtu.be/U46fJ2bJ-co?t=2780 https://youtu.be/U46fJ2bJ-co?t=2780 and Ryan asked Bjarne about memory safety. Bjarne brushes it off and says that in almost all cases where we see memory safety issues, they are either 1. Being written in C style C++ and not using "Modern C++" 2. Being written in C He then goes on to say say that Modern C++ and where it is necessary, hardened libraries, go a long way to making these problems non issues. I'm not a C++ guy, so how much of this is true? What do the C++ developers think about this? I've postd the whole message if people would like to read. It's about 46minutes into the video Ryan: One thing that I think C++ is uh infamous for is kind of like memory safety issues or kind of foot guns that exist there. Bjarne: I'm so tired of that. Um I haven't had those problems for years. Um, and somebody did a a study of the obvious problems with buffer overflows and um people hacking in using that kind of stuff and uh almost all of the uh these cases when people writing C style code or in C and uh Herb Server has a a talk with with actual numbers and they they are quite significant. It's it's sort of that kind of problems more than 90% are for people that don't write modern C++. They they use raw pointers to pass things around without um the number of elements. No fat pointers, no spans. um you you have them in C++. You can use them. You can use uh vectors. We have hardened libraries. Everybody has hardened libraries that that does the runtime checking. Uh Apple has it. Google has it. Microsoft has it. It's just not standard till now. C++ 26 has a hardened option that are standard. uh and the work I'm doing on profiles will give you a way of guaranteeing that you don't do the stupid things. Um so anyway, uh fundamentally theoretically the problem was solved many years ago and people just do what they've always done and get the problems they've always had. And uh that makes me sad and uh it's one of the things that makes me work on uh coding guidelines and on enforced profiles and on education. I mean education is one way to solve the problem. Is there a way to get the compiler to just prevent people from doing all those risky things? And is that enabled by default in modern C++ today? No, but it should be. I'm proposing that for C++ 29. Uh the simpler versions of that should have been in in in uh C++ 26, but there are still a lot of people even in the C++ standards committee that are very devoted to uh their old code and their old ways of doing things. Um there's people who says you should only standardize what is common in industry. But when the bugs are common in industry, you should do something else. The standards committee is a a topic I
- 4mo ago
- uecker 4mo agoThere can be made very good arguments why C is less safe than Rust, but null pointer dereferences which are perfectly safe everywhere except on weird platforms (and usually could be made safe even there by turning on a compiler flag) seems a very misleading argument. And as as the Cloudflare incident showed, a Rust unwrap can have equally bad consequences. (or as Ariane 5 showed, a safe overflow in Ada can have explosive consequences)
- blub 4mo agoThese Rust discussions typically contain grains of truth wrapped into exaggerations while downplaying or ignoring the two big issues of Rust, which are complexity and out of control dependency trees. For the first issue of complexity, the reply is along the lines of show me the code and then either nitpicking that to pieces or explaining in several paragraphs how the behavior is perfectly reasonable and in fact quite easy to understand. Beginners get intimidated, professionals don’t have time to write novels on HN. Complexity in Rust is systemic. It’s little things accumulating and amplifying each-other that add up to having to spend significant time just designing types to satisfy the static analyzer. Many Rust programmers seem to see the type system as a hammer to be used liberally, an predilection also known in the C++ metaprogramming community. On the second topic (also present in this thread) the counter-argument is that other languages do it too and nothing bad happened so far. The former is not valid, because Rust is uniquely bad in its competitor group and security by waiting is not a valued approach.
- hurril 4mo agoI would argue that what you call complexity here is better referred to as explicit or visible complexity, as compared to hidden or implicit commplexity. The complexity as such comes with the domain and its application; but with Rust you can see it and you are forced to deal. With C++ you can get away with pretending that it is in fact not there. This is honestly not intended to pick on C++ as a Rust fanboy, however. It really isn't. For instance, to be a little unpolished, I would shrug off the unwrap incident as doing it the C++ way and pretending that the complexity does not need to be solved right then and there because ItShouldNotHappen or IKnowWhatIAmDoing. I prefer Rust over C++, but I do not hate C++. This isn't even about C++ anyway. When it comes to out of control dependency trees, I agree with you. But there is a trade off here too and that is that either you implement the thing or you externalize it. I use both approaches myself and am in no way excusing anything or attempting to be Rust's defense lawyer. There definitely seems to be a leftpad-problem brewing in the Rust community.