How memory safety CVEs differ between Rust and C/C++
Posted by nicoburns 1 day ago
Comments
Comment by john_strinlai 1 day ago
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)
Comment by mk89 1 day ago
"Especially now" all these infosec folks "need to get CVEs fixed because compliance/SOC2, etc" and they will be even more up your a*!
Something has to change with how compliance works. It is so outdated and crazy.
Comment by tptacek 1 day ago
Comment by mk89 1 day ago
Comment by 1718627440 1 day ago
Comment by tptacek 1 day ago
Comment by mk89 1 day ago
You need to fix also moderate/low CVEs within a certain time frame.
So CVE count becomes relevant, because the target is zero, although it doesn't mandate "zero CVEs" but that's finally what the desired outcome is.
It's basically unrealistic to ignore that number, because it's unlikely that you have a steady 1000 CVEs (that are being continuously fixed and new ones discovered), but more like "a few exceptions".
Comment by tptacek 23 hours ago
Comment by kasey_junk 23 hours ago
Comment by tptacek 22 hours ago
Comment by tialaramex 20 hours ago
Comment by tptacek 19 hours ago
Comment by tialaramex 16 hours ago
I of course said it isn't, because as we both know, it isn't.
"That's not the job" is I think the most useless possible observation here. The best outcome from audit isn't that you checked all the boxes, that's just resources expended for no benefit, the best outcome is that audit found a nasty problem early so that you could fix it now. The biggest problem we have in the Web PKI with auditors is that they'd so much rather tick boxes than tell their client - who they are billing $$$ - where the problems are. This presumably feels good to the suits, but if there's a problem and the auditors don't tell you the chances are somebody else finds it and then you're in worse trouble.
Comment by tptacek 15 hours ago
Comment by john_strinlai 1 day ago
i am an infosec folk (:
Comment by mk89 1 day ago
In my experience it is becoming basically ridiculous that we disallow compliance based on a number of cve, their level, etc. It's just a checkbox, but it has nothing to do with security.
Comment by mk89 1 day ago
I'd like to know how a "critical CVE running in your software for 29 days" is acceptable from a security standpoint. With nowadays tooling, these AI agents can take you down in no time if they target you.
Compliance the way is done today is basically outdated, but everyone has to follow these rules to sell software basically.
Comment by tialaramex 20 hours ago
1. There's a "critical" severity security issue because we have an obsolete version of some Perl library on a machine that's exposed to outsiders (ie has a public HTTPS website)
1a. The perl library isn't used by any of the software running on that machine, it's presumably either left over from software we no longer use or it was installed to run somebody's one-shot Perl script, possibly years ago, maybe even for a prior incarnation of that system, with the present one installing that library because it's just easier than figuring out which libraries are still needed...
1b Severity CRITICAL. Actual threat: ZERO
2. .NET 8 is obsolete, machines with the .NET 8 CLR are flagged as insecure.
2a. .NET 10 isn't obsolete, that's still supported, in many cases the exact same code, re-compiled with a 10.x version not 8.x was shipped by Microsoft. Is that true for all the cases we care about? Nobody knows, nobody is even interested in working out. Flagged instances will be turned off if they're not fixed so "just" fix it. Busy work.
2b. Severity HIGH. Actual threat: Unknown, possibly negligible?
As with Mythos these "AI agents" which can "take you down in no time" can't do the impossible, this isn't a Hollywood movie, mumbling about AI and critical severity CVE doesn't turn that Perl library nobody was using into an actual threat.
Comment by mk89 16 hours ago
This is the main issue about compliance nowadays. In a fedramp scenario you would very likely have to prove that it's unreachable, and you might even risk compliance over it.
From an attacker perspective they don't know the lib version you're using, but bruteforcing / finding patterns faster than a hacker can? That's what I believe AI can do. This is why for me CVEs are a useless metric, the number and/or criticality. It's a simple security control but they are giving it so much importance. Then you "forget" to secure access to your mcp server and this leaks company info, but hey, zero CVEs, soc2 compliance check check check.
I think it's a good practice to fix as many CVEs as possible, to have a clean/updated codebase, but I am of the opinion that if someone wants, with the tools they have nowadays, they will find a way in. Of course, using a lib that has obvious security issues for input validation, for example, should be a no-go. However, we're reaching a point of ridicule (like you said above, a critical CVE but unreachable).
Comment by jamesfinlayson 1 day ago
Comment by jiggawatts 1 day ago
Comment by jamesfinlayson 12 hours ago
Comment by physicsguy 1 day ago
Comment by cfdryhh 1 day ago
Comment by kkishahva 1 day ago
Comment by mswphd 1 day ago
> 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.
Comment by dtornabene 1 day ago
Comment by kwveddlsjggej 1 day ago
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.
Comment by uecker 1 day ago
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)
Comment by 1718627440 1 day ago
For availability and stability concerns, the C approach is actually better, but for security and reproducibility, it is not.
Comment by uecker 20 hours ago
In any case, you can also configure GCC to not do this, and you can also configure it to insert explicit null checks before dereferencing a pointer. So C can offer you security and reproducibility (in this aspect).
Comment by Ygg2 1 day ago
Arguably less bad than silently corrupting your data and forcing you to do CAPTCHA everywhere.
Which is what the parallel Perl(?) component was doing at the time.
Rust solution gave a clear signal something was wrong, the other solution was slowly annoying everyone and pushing them away.
Comment by uecker 20 hours ago
Comment by Ygg2 19 hours ago
And the Rust wasn't the root cause but corrupt configs were being erroneusly duplicated.
Comment by uecker 19 hours ago
In any case, I largely tend to agree with you that this is better in most scenarios (not for the cloudflare incident though). But a segfault in C for a null pointer dereference would have exactly the same result, which is why null pointer dereferences are a terribly example if you want to show the advantages of Rust.
The only example I know where I think Rust clearly has a real advantage are lifetimes.
Comment by blub 1 day ago
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.
Comment by hurril 1 day ago
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.
Comment by uecker 20 hours ago
Comment by hurril 19 hours ago
What do you mean by complexity in this context and in what way does Rust carry a lot of it?
Comment by uecker 6 hours ago
Comment by hurril 4 hours ago
In Rust the compiler is going to have a problem with your code unless you are explicit about borrowing/ ownership, gcc won't care. Which is the more complex thing there?
Same goes for the polymorphism. Looking at languages without parametric polymorphism, you instead see casts and inheritance trees. Not picking on old Java here, but is this more or less complex?
Let's talk some about unsafe as well. In C or C++, for instance, there is a global unsafe surrounding all the code, so if someone has problem with unsafe, why would they pick on Rust where "unsafety" is optional?
Same goes for unwrap. Unwrap is basically a deref combined with a _safe_ crash if the deref was not successful at runtime. Do that in an unsafe language and you have an access violation best case. Or just silent corruption. Which is more complex?
Comment by cesaref 1 day ago
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.
Comment by hathawsh 1 day ago
Comment by favorited 1 day ago
Comment by vintagedave 1 day ago
If everyone expects specific behavior - ie it’s in the contract - you require that contract.
Comment by lathiat 1 day ago
We generally did this in the avahi libraries, be fairly liberal with asserts that "shouldn't happen", it is a source of complaints though because basically you can be using a third party library that uses avahi and have your program crash due to a bug in that library, or in avahi. It's extra fun when using some historical libc systems such as "NSS" and you load a plugin to do hostname resolution, which nss-mdns does.. now you can have any program on the entire system crash if you are assert happy.
On the one hand I agree that if the result is going to be memory un-safety then perhaps you should assert, but more ideally you'd just fail gracefully and throw or return an error. That can sometimes be tricky though, if there is no good way to return an error or return a NULL value or similar. Depending on the API.
Of course, this is the entire reason behind the error return traditions of Golang and Rust, e.g: https://doc.rust-lang.org/book/ch09-00-error-handling.html
Which basically says what I said above :)
But in the case of curl_getenv, returning NULL seems a valid possibility (https://curl.se/libcurl/c/curl_getenv.html) as that is indicated to be done if you don't find the requested environment variable. Arguably the NULL environment variable is not found. so, this feels likely to be acceptable. Though I could see an argument for you now assuming the environment variable you were actually looking for not existing, but you didn't actually ask for one, and now your logic is broken and maybe you introduce a different class of security bug because you change your behaviour based on some environment variable not existing.
As always everything is a trade-off...
Comment by josephg 1 day ago
Comment by pjmlp 1 day ago
Comment by pjmlp 1 day ago
Ah but what high integrity computing, well there neither crashes nor memory corruption are welcomed, hence programming guidelines and certification workflows that would make most C devs cry with the language features they are allowed to use, and how each line of code gets analysed by tools and humans.
Comment by hathawsh 1 day ago
Comment by dwattttt 1 day ago
Comment by jstimpfle 1 day ago
But it's >> 99.9% true that this will just crash even though it's acshually UB, nasal demons and so forth. Now raise this << 0.1% likelihood that it isn't true on some system with some compiler and build flags, to the power of the number of distinct deployed configurations out there, and you get the result which is the correct engineering decision of just moving on instead of spending your life filling straightforward code with pointless boilerplate assertions.
NB it can make sense to assert nonnull when the condition won't be tested on all code paths or the intention is otherwise not super obvious.
Comment by lmm 1 day ago
Is it though? Linux saw enough bugs from that kind of issue that they now build with -fno-delete-null-pointer-checks and accept the (supposed) performance penalty.
Comment by uecker 1 day ago
In general on a system where you trap when accessing the zero page, this optimization should be safe and a null pointer dereferences should (safely) trap.
Comment by lmm 1 day ago
If you mean that C compiler writers "should" prioritise sanity over high scores on microbenchmarks, then I agree. However in practice they do not and this optimization is not remotely safe.
Comment by uecker 1 day ago
(EDIT: what is not safe is indexing into a null pointer. For this you need to be safe you need -fsanitize=null)
Comment by lmm 1 day ago
Comment by jstimpfle 1 day ago
We are talking about an extremely simple straightforward API with an obvious contract. It's good enough for this function to reliably surface almost all wrong uses with a segfault immediately. Wrong use will result in segfaults and otherwise bugs and crashes. The goal is not to work when used wrong but to work when used right. You cannot save the world from scratch in every little function. You still have a job to get done, and you have to move on.
Comment by lmm 1 day ago
Or you can take all of 10 minutes to put sanity-check assertions at the start of all your public-facing API functions, eliminating a source of security bugs, get on with your life, and worry about the performance implications as and when it becomes a problem (hint: it's never going to become a problem).
Comment by jstimpfle 1 day ago
There are so many other interesting and relevant invariants that are usually in an API contract that are much harder or impossible to check upfront (let alone express formally in a type system), and even violations may be impossible to diagnose when they happen.
People focus on NULL because that's the only way they can apply their silly limited type systems. But NULL checks give very little return for investment. In practice, you'll see templated Option<T> types and whatnot, and when I have to look at or even work with such code I want to kill myself because it's so painful.
Comment by lmm 10 hours ago
Comment by jstimpfle 4 hours ago
Given a, b, c input parameters to my func, it must hold that that a->m->t == b->t. c->mutex must be held, and c->cond is the condition variable that goes with c->mutex and will release any waiters on the buffer contained in a.
Or: Integer x is representable using 12 bits only, Integer y should be a multiple of N and I have a integer s is used as a bit-shift that should be less than 8.
Or: I need to guarantee that no locks have to be taken and no allocations have to be made on this complicated looking codepath. While holding a lock, we must not do any syscalls (syscall a, b, c are ok though), and surely not make any logging calls.
I know only one system that can express this, it's called STRAIGHTFORWARD CODE, and it requires doing engineering and casual logic out-of-band, and yes it does include making mistakes and repairing them incrementally.
I don't know a type system that would let me explain these things to me and tell me where I was wrong. But maybe you can show me, with 5 minutes of actually trying?
Comment by lmm 3 hours ago
So define a wrapper type that represents that invariant (it's not going to take up space at runtime), where the only constructor enforces it?
> Integer x is representable using 12 bits only, Integer y should be a multiple of N and I have a integer s is used as a bit-shift that should be less than 8.
Those are all standard things that already exist?
> Or: I need to guarantee that no locks have to be taken and no allocations have to be made on this complicated looking codepath. While holding a lock, we must not do any syscalls (syscall a, b, c are ok though), and surely not make any logging calls.
Sounds like a pretty standard free monad case? Define a command algebra in which the "ok" syscalls are a subtype, and then require that the thing you want to only use the ok calls to have a type that reflects that?
Comment by jstimpfle 3 hours ago
> Define a command algebra in which the "ok" syscalls are a subtype
Dude, it's clear you're not doing any actual work. You are living in an ivory tower, and you underestimate the complexity and detail and volatility of real world applications by at least 3 orders of magnitude. You don't understand how to modularize and contain complexity.
You _cannot_ complete a project with this attitude.
You are ignorant of the fact that a type system is necessarily a blunt simplification of the real complexity. Therefore, use of types must be pragmatic, and actual logic must be coded in normal code (which should be obvious but it isn't to type theory weirdos). Otherwise, you require dependent typing or whatever, and you will have to write your code twice, once in a usable programming language and once in a very unusable programming language. Much more than only twice actually, given that all the implicit detail should apprently go explicitly formalized at the type level.
Just to make sure I'm not entirely talking out of my arse because I'm so incredibly annoyed by your otherworldly proposition, I asked an AI about the sel4 microkernel. It consists of 10,000 lines of C code (that says a lot about its practical utility, which is very limited), and of 1,3 million lines of manually written proof code (which says a lot about the practicality of proving).
Comment by dwattttt 1 day ago
Comment by jstimpfle 1 day ago
Comment by dwattttt 1 day ago
Comment by jstimpfle 23 hours ago
Comment by dwattttt 15 hours ago
My proposition is that "it's silently ok" isn't likely enough, which is in line with your position on "don't extend the contract to accept null". So what's left is crash, or something worse.
So if those are your choices, don't waste time justifying that a null can't get there, just add a check to ensure you get the better behaviour. It takes seconds.
Comment by jstimpfle 4 hours ago
You are requiring yourself to find a valid outcome for an input that doesn't make _any_ sense in the context of what your application is meant to achieve. How is that not a Sysiphean task?
Comment by dwattttt 2 hours ago
You're actually pruning the valid state space; before, when the null value is passed to the function, there are more operations performed that have uncertain consequences. If you assert-and-fail when you get the null input, you've pruned those states.
Comment by jstimpfle 2 hours ago
"Because no one is expecting it to work if a null is passed", so you can do whatever. If you write an assert for every pointer passed to every function, that will be a lot of asserts, for pretty much the same outcome in practice. Asserts are just marginally more ergonomic when they trigger, but are a nuisance in the code often. So my position is to use them judiciously, but not overdo it, be instead focused on the actual task.
When the lack of non-null assertions is an actual problem during development, you have much larger structural issues.
Comment by dwattttt 2 hours ago
Comment by jstimpfle 1 hour ago
I thought so too, for many other things, and did so too in practice. Then I was doing thousands of little tasks in order to improve "security" and "correctness" and "proving everything", and never got to actually do anything useful, and my code became bloated to the point it didn't get to do much useful work.
Now I'm more considerate, trying to weigh everything in the larger context, is it REALLY required to get my job done?
Comment by Dylan16807 1 day ago
Comment by jstimpfle 1 day ago
Comment by asveikau 1 day ago
Comment by thayne 1 day ago
Indeed. Adding an assertion to a single function isn't a big deal, but if every function has to check all of it's arguments, that's going to add up. And even if you could have the assertion only in debug builds, that isn't enough unless you have a very exhaustive test suite, because an edge case could trigger undefined behavior in production in a way that wasn't exercised during testing.
In fact, the fact that the rust compiler adds runtime checks for array indexes if it can't prove the index is in bounds is a criticism some c programmers have of rust.
Comment by saghm 1 day ago
And the fact that after a half a century we're still debating how much we really need to care about U stuff like this when we get severe bugs in a major piece of software written in C seemingly every week is a criticism that pretty much all Rust programmers have of C.
Comment by uecker 19 hours ago
Comment by pjmlp 1 day ago
Most systems languages, with exception of C, have ways to do bounds checking, even C++ and Objective-C, by using the respective collection classes.
Comment by gkfasdfasdf 1 day ago
Comment by blueg3 1 day ago
Comment by 1718627440 1 day ago
Comment by bawolff 1 day ago
Comment by eptcyka 1 day ago
Comment by f33d5173 1 day 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.Comment by eptcyka 1 day ago
Comment by saghm 1 day ago
Comment by f33d5173 1 day ago
Comment by eptcyka 23 hours ago
Comment by saghm 22 hours ago
Comment by wahern 17 hours ago
Yes.
#include <stdio.h>
#if __has_include(<stdcountof.h>)
#include <stdcountof.h>
#else
#define countof(a) (sizeof (a) / sizeof *(a))
#endif
void
foo(int n, int a[static 1][n])
{
printf("sizeof *a: %zu\n", sizeof *a);
printf("countof *a: %zu\n", countof(*a));
}
int
main(int argc, char *argv[])
{
int array[argc];
foo(countof(array), &array);
return 0;
}
$ ./foo
sizeof *a: 4
countof *a: 1
$ ./foo 2 3
sizeof *a: 12
countof *a: 3
Tested using Apple clang 21.0.0 and gcc 15.2.0.The syntax for using passed VM arrays is stilted; you're operating on a pointer to an array, which can get confusing and is error prone. Because of the semantics for array passing and need for backward compatibility it's too easy to get it wrong without the compiler catching mistakes and complaining. Though, the C2y _Countof operator is required to error when used on a non-array, so using _Countof(a) instead of _Countof(*a) will fail. (GCC and clang also have warning diagnostics that work for the fallback countof macro.) And there's no way (or no easy way?) to ask compilers to inject automatic bounds checking when operating on arrays, at least outside non-production debugging modes like ASan.
But C is getting there, slowly.
Comment by tialaramex 1 day ago
Comment by __s 1 day ago
His mistake was making _all_ reference taking functions also accept null. In Rust functions opt into None | Some
This comes up with C# which must have default(T) so references default to null. In Rust there is no general default(T) that must always resolve
Comment by tialaramex 1 day ago
Comment by saghm 1 day ago
Comment by selfmodruntime 1 day ago
Comment by josephg 1 day ago
Comment by uecker 1 day ago
Comment by bitbasher 1 day ago
However, Rust seems to trade memory safety vulnerabilities for supply chain risk.
Comment by insanitybit 1 day ago
Thankfully the community has built `cargo-vet`, which is basically a best-in-class distributed auditing system.
Comment by anuramat 1 day ago
how is rust special in this regard?
Comment by bitbasher 1 day ago
1. Each crate you depend on generally comes with dozens of its own dependencies.
2. A large number of crates have few downloads. You can use blessed.rs to try an find "trusted" dependencies.
3. Cargo comes with "build.rs" for compile time code execution. Basically, your code (or your dependencies) can run arbitrary code when it first gets compiled.
4. A Github account is required to publish crates to crates.io (this sucks if you don't want to be locked in to another Microsoft system).
These are just a few of the issues I have had with Rust before switching off it.
edit:
Point #4 is personal for me. I have multiple crates published on crates.io and I cannot log in and manage them because I deleted my GitHub account a long time ago. I wonder if someone could create a GitHub account using my name and claim ownership of them...
Comment by okanat 1 day ago
This is no different than C++. C++ standard library made so many compromises in the name of ABI compatibility almost none of the library is actually usable for any use case. So people start to quickly add things like boost, abseil, folly, Qt, asio, imgui, doctest etc. There are millions of small libraries everywhere too!
Their CMakeLists files or conan packages also execute random commands and in the case of supply chain compromise they are as vulnerable as Rust. Actually CMake is so complicated that one can hide an exploit a bit better than build.rs.
I don't think it is a good thing either way and both toolchains should implement ways to limit execution and isolate code generation. For the packages we also need to see stronger ownership and signing guarantees. Maybe even a domain-based validation system with TXT-keys against takeovers. Allowing random people to just register and typosquat packages is not a good idea.
Comment by physicsguy 1 day ago
Comment by tobias12345 1 day ago
I have not yet looked at any C++ code base > 1 milliom lines where I did not find at least 3 copies of zlib. Often just the compression or decompression function copy and pasted into a random file. Which version? No idea. Was it patched? Likely. Is there any documentation on how to update this? Absolutely not. Was it easy to find? No, some specialists even rename the functions so that users linking to the system zlib do not get into symbol conflicts. I have heared way to often that it is so much simpler to just copy a class over from abseil, or whatever other library than to depend on it.
Sure, you do not see dependencies, the functionality those provide are still there somewhere though -- either hidden away or in the form of reimplementations. You just do not know... and what you do not know about you can not maintain.
Comment by armitron 1 day ago
Comment by okanat 11 hours ago
https://archlinux.org/packages/extra/x86_64/apache/
They look no different than your usual Rust crate. And their full flattened dependency trees already exceeds hundreds of packages.
C/C++ libraries have much more complex build systems with many optional features shipped inside the library. Just think of curl and how many protocols it supports.
Rust's build system, however, is extremely simplistic and limited. So to have things like multiple backends for rendering, parsing, serializing etc. you have to split your library into multiple crates due to limitations Cargo impose on you. So the full equivalent of curl will be 20+ individual crates.
I think the hundreds of dependencies is overblown due to this effect. I maintain my argument. C and C++ projects are just as complex and vulnerable. CMake and fully binary distribution via Linux package managers just hide their complexity.
Comment by dwattttt 1 day ago
It's also an indirect risk, but I've seen C projects reimplement things that would be a dependency in Rust, and introduce subtle (or not subtle) bugs.
Comment by pjmlp 23 hours ago
Additionally, most C libraries tend to come via UNIX package managers directly, and then consumed via CMake, pkg-config or what not.
I do agree Rust dependency trees are a problem, for security, and always compiling everything from source.
Comment by afdbcreid 1 day ago
Comment by bitbasher 1 day ago
Maybe some day though!
Comment by anuramat 1 day ago
even 4 -- fuck microsoft of course, but other than that: you always need some sort of an account to publish stuff
Comment by dochtman 1 day ago
AIUI the crates are actually linked to the account via a different identifier, not directly to the username.
Comment by saghm 1 day ago
Why not just make a throwaway account with that username and test it, and if it works, just don't save the password or ever log on again? If it's something you care about personally and it's really been that long, I'm kind of confused why you haven't already tried this rather than just vaguely implying risk that seems pretty straightforward too verify. (It's fine if you just legitimately don't care, but it doesn't seem like it's really a personal issue for you in that case)
Comment by tcfhgj 1 day ago
Comment by bitbasher 1 day ago
Perhaps a Makefile could be considered arbitrary code execution, but we've been running Makefiles for 50 years and we haven't had the supply chain issues we see in NPM, etc.
Supply chain risk was always considered in the C/C++ world... think back to Ken Thompson's 1984 paper "Reflections on Trusting Trust" where he questioned if you could even trust your compiler.
Perhaps the main difference between the Rust and C/C++ world is less about the tooling or languages, but more cultural? I don't know, just something to think about.
Comment by dralley 1 day ago
Comment by armitron 1 day ago
Rust has thrown the baby out with the bathwater in that regard resulting in software that is practically impossible to audit without putting in enormous effort.
Comment by galangalalgol 1 day ago
Comment by anuramat 1 day ago
thanks, can't believe the idea isn't more mainstream -- I've never thought dependency safety could be a thing
Comment by galangalalgol 1 day ago
Comment by selfmodruntime 1 day ago
Comment by dundarious 1 day ago
Comment by thegrim33 1 day ago
Comment by okanat 1 day ago
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... 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.
Comment by jpc0 1 day ago
Enable warnings and WError
Use clang tidy and other static analyzers
Actually use a modern compiler and enable the safety features they ship with
Most of these things have solutions that would take years of work in an existing project so it isn't done
And it takes significantly more effort to write good modern C++ code than Rust code
So Rust wins
But I don't like writing Rust code, I do enjoy writing modern C++ code, the tradeoff is modern C++ can be a tooling nightmare... Try shipping a modern stdlib on an old platform, it is truly infuriating, I don't want to be a build systems expert but I need to be to use a safer alternative.
Comment by rcxdude 1 day ago
Comment by pjmlp 23 hours ago
Any language that isn't copy-paste compatible with C (or a subset of it), wins.
That is the biggest issue, old habits and old teaching materials keep working, a plus, and a curse.
Comment by physicsguy 1 day ago
This was always a pain point in C++ embedded space, to be fair.
Comment by pornel 1 day ago
This is the blind spot that prevents Bjarne from taking significant steps needed for C++ to catch up. He's still seeing C/C++98 as the problem to solve, while Rust sees Modern C++ as the problem to solve.
Comment by pjmlp 23 hours ago
The problem of TypeScript, is that you can still write JavaScript with all the WATs, same applies to any language that tries to be TypeScript for C.
However many of us actually think that Rust is also not the answer for everything, there are plenty of safe languages that could be used instead of C, C++, Rust for plenty of scenarios, and aren't because of cultural issues.
Comment by afdbcreid 1 day ago
And there are plenty of ways to cause UB with modern C++ idioms.
Comment by pjmlp 23 hours ago
Beautiful modern C++ unfortunately only exists in conference slides, recent C++ books, and top performer teams.
My main use for C++ outside hobby coding, is to integrate native code into managed runtimes, most of the time the code looks closer to C with Classes than anything past C++11, even if it was newly written yesterday.
Comment by shevy-java 1 day ago
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/
"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.
Comment by ghosty141 1 day ago
I think it's also a big sign that the linux kernel adopted rust and not c++. (only for small parts but still)
Comment by tialaramex 1 day ago
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.
Comment by cesarb 1 day ago
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."
Comment by pjmlp 23 hours ago
It was mostly a Linus issue, and not wanting to fix what were the root causes of the regressions.
Comment by physicsguy 1 day ago
Comment by saghm 1 day ago
Comment by pjmlp 23 hours ago
Comment by saghm 20 hours ago
At a higher level, I've noticed a long-term trend where dismissals of Rust from C++ proponents have continued to grow increasingly abstract; the line of reasoning basically seems to be that how Rust is used in practice can be ignored as long as there's a sufficient theoretical argument for C++ being able to do the same thing. This is a remarkable retreat from the previous objections to Rust being impractical compared to C++ which I'd argue is itself evidence of the ground that Rust has gained in the past several years. It seems to have happened without the C++ community noticing though, which at least in part seems to come from some cognitive dissonance; in your two replies to my comments in this thread, you demonstrated this yourself by arguing on pragmatic grounds about how C++ is used in practice in this comment but then rejecting criticism of C++ in your other comment by asserting that a "recipe" for memory safety is enough to dismiss concerns about how pretty much no real-world project actually achieves this.
My (obviously biased) perception is that the shortcomings of Rust tend to be pretty widely agreed upon by the experts in the community and mostly dismissed by people who honestly aren't nearly as experienced in the language, whereas with C++ the most expert members of the community seem prone to handwaving away concerns that deserve a lot more attention.
Comment by pjmlp 23 hours ago
Comment by 360MustangScope 1 day ago
If they rewrote it in C++ again, they would have most likely got the same result because they got a chance to fix a design that might not have been most optimal.
Comment by saghm 1 day ago
Comment by cogman10 1 day ago
Comment by tialaramex 1 day ago
This speculation has been offered every time. It's not crazy to think this might be true, but it's also not crazy to think that if C++ keeps leaving performance on the table and Rust doesn't that adds up for real projects.
When Titus wrote "ABI: Now or Never" in 2020 he estimated 5-10% aggregate loss. Things that you could fix, if you started over, but C++ refuses to do that because of ABI and so it doesn't have these fixes, whereas in most cases† Rust does. So I can well believe that a blow-for-blow port could get you 10% perf win.
† One of the examples Titus cites is the "Small String Optimization". Rust deliberately doesn't do SSO for its standard library collection String, but several really nice SSO optimised types are available, including ColdString and CompactString, which are way better than what's provided in C++ if that's what you need.
Comment by tick_tock_tick 1 day ago
Realistically the difference doesn't matter much and if you're writing code that must be as fast as possible your writing unsafe Rust that looks a lot more like C/C++ then anything Rust.
Comment by josephg 1 day ago
What metaprogramming does C++ have that rust is lacking?
If you need more than traits + generics, rust also has proc macros. Proc macros are essentially portable compiler extensions. They take in a stream of symbols from the user's program at compile time and emit rust code that gets passed straight to the compiler. You lose out on syntax highlighting and they make compilation slower. But macros are essentially compile-time code gen. They work great. In rust, you can do things like JSX at compile-time without any special compiler support. (See: leptos.)
> Realistically the difference doesn't matter much and if you're writing code that must be as fast as possible your writing unsafe Rust that looks a lot more like C/C++ then anything Rust.
I agree that the difference is small in practice. Good rust often does look a lot like C - with plain structs everywhere and lots of global-ish scoped functions.
But I don't agree about unsafe. I've spent some time porting well optimised code from C to rust. I generally find I need far less unsafe code than I expected. I ported a ~500 line skip list implementation from C to rust a few years ago. I think my rust code ended up using just 2 unsafe functions. The rest of the code didn't need any unsafe at all.
My skip list was a monster to debug in C because most logic bugs ended up corrupting memory. As a result, a bug in one function caused crashes in far away code. In rust, debugging was much easier. There wasn't any "spooky action at a distance". And that let me reason about the code much more easily. As a result, once I got it working I ended up adding a few more optimisations in rust that I was too overwhelmed to write in C. The rust code is now ~2-3x faster.
If you're interested:
https://github.com/josephg/jumprope-rs#benchmarks
C code is here: https://github.com/josephg/librope
Comment by pjmlp 23 hours ago
Compile time execution, and compile time reflection, with the same syntax.
Proc macros are still a kludge having to depend on syn crate, and some stuff used to depend on nightly, is that still the case, I don't keep track?
Additionally type specialisation, and explicit templates.
Comment by steveklabnik 20 hours ago
Comment by pjmlp 20 hours ago
Comment by saghm 1 day ago
The point the parent comment is making is that this doesn't really matter if no one actually does do these things in C++. It's absolutely wild to me how quickly the arguments in favor of C++ instead of Rust have reversed in about a decade; people used to argue that the benefits of Rust were all theoretical and in practice people who were used to C++ could write it perfectly fine without safety issues, and now it's somehow that the theory that gives C++ the advantage and we don't need to care about whether those supposed advantages ever actually exist in practice.
Comment by tialaramex 1 day ago
I don't think that makes a lot of sense even theoretically because of e.g. aliasing, but it doesn't matter because as I said, C++ chooses to be slower, Titus gives a number of examples where we know how to do X fast, and that's how Rust does X - in theory C++ could X the same way, but none of the three C++ compilers people actually use do it, because they picked wrong and then froze their ABI and won't thaw it.
Comment by tick_tock_tick 1 day ago
Aliasing has yet to provide any real benefit for Rust and a hell of a lot of issues. Maybe one day it will be a big win but realistically anyplace that aliasing matter c/c++ will just drop __restrict on it.
Comment by josephg 1 day ago
Like what?
> Aliasing has yet to provide any real benefit for Rust and a hell of a lot of issues.
Yeah, the performance wins so far are quite small. But rust's noalias-by-default did unearth a whole lot of latent bugs in LLVM. Even if you don't care about rust, its great that rust led LLVM to track down and fix these bugs. They affected C/C++ code too.
> realistically anyplace that aliasing matter c/c++ will just drop __restrict on it.
Is there a way to tell? When I'm writing C, I have no idea if using restrict will help other than staring at the assembly. (Or just trying it). I'm also leery of using restrict in C because its so hard to audit callers. How do you know when restrict is safe?
Comment by 1718627440 1 day ago
It's also a statement, whether you want callers to pass the same object to different parameters. If that doesn't make sense or you don't want that, write restrict.
Comment by drysine 1 day ago
Could you elaborate on that?
Comment by tialaramex 21 hours ago
C++ std::string can contain up to 15 (other popular implementations) or 22 bytes (libc++ from Clang) of inline text, and the data structure itself is either 24 bytes (Clang again) or 32 bytes of storage. Here's Raymond Chen: https://devblogs.microsoft.com/oldnewthing/20240510-00/?p=10...
CompactString is 24 bytes of storage with all 24 bytes as potential inline text. When the 24 bytes are valid UTF-8 text, then that's the content of the CompactString e.g. "https://example.org/cool", if they aren't the last byte will be invalid UTF-8, and this signals whether some of the other 23 bytes were inline UTF-8 (and if so how many) or whether they should be interpreted as a pointer, size and capacity.
ColdString is a radically different idea, it's 8 bytes of unaligned storage and it's one of three things: 1. 8 bytes of UTF-8 text, as before we can tell by whether it's valid UTF-8 text or 2. 0-7 bytes of UTF-8 text, prefixed by an invalid UTF-8 byte telling us how many of the remaining bytes are text or 3. An encoded pointer to a length-prefixed data structure, signalled by the presence of the UTF-8 continuation marker bits which should never be present in the first byte of a string.
I really like ColdString because it's so much in the "use the whole buffalo" spirit of these modern safe yet high performance types. UTF-8 has what are called "overlong prefixes" because it was invented before Unicode decided it would never grow beyond U+10_FFFF and these are often just a useless impediment, but ColdString uses those prefixes.
Comment by drysine 13 hours ago
How do CompactString/ColdString compare to std::string implementations performance-wise? From the looks of it, they must be somewhat slower than C++ strings
Comment by tialaramex 4 hours ago
Comment by pjmlp 23 hours ago
Depends on the domain, there are enough fields where Rust still doesn't have an answer for.
Example, the compilers it depends on (botstraping on Cranelift when?), Khronos and POSIX industry standards, HFT, HPC, console devkits, AI frameworks, VFX reference platform,....
It will get there, eventually, maybe.
Comment by FpUser 1 day ago
On publicity side / propaganda / some specific areas you might have a point. Practically amount of C++ code being in active development (I wat to stress this particular point) dwarfs that of Rust despite all that high profile pressure.
Personally I consider languages as just a tool and do not get hung up when client prefers this or that and I have developed all kinds of software in many languages.
If asked for my own opinion - for general development I consider Rust very restrictive and poor expression-wise comparatively to C++, I think it is a case when developer become servant of a tool.
P.S. last sentence edited
Comment by reallyinchaos 1 day ago
Comment by vouwfietsman 1 day ago
I don't think its fair to attribute it to lack of skills or bad intent, unless there's some proof to any of it.
Comment by reallyinchaos 1 day ago
Comment by jooops1 1 day ago
Comment by Decabytes 1 day ago
1. 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
Comment by josephg 1 day ago
> 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
Maybe the android team could have gotten the same benefits by simply auditing and modernising their C++ code? I'm not convinced. Google has some amazing engineers. They've been using hardened standard library variants for a long time - much longer than they've been part of the C++ standard. If google is still getting large security benefits from adopting rust, I think the benefit in rust is real and Bjarne Stroustrup is wrong.
[1] https://blog.google/security/rust-in-android-move-fast-fix-t...
Comment by blub 1 day ago
First of all, Rust is default safe. In C++ developers always trade performance for safety, in Rust they just swallow the penalty (which is often still performant enough). C++ code will often not be as memory safe as it could because someone decided to not use particular checks (like compiler-driven integer overflow checks).
Secondly, Android C++ code is not particularly high quality, also when it comes to memory safety. A lot of it is also quite old. I would consider it your average massive project, not a masterpiece coded by amazing engineers.
Thirdly, it has a massive target on its back and is under attack by pretty much everyone. They have to use whatever they can to keep up with the attackers.
Several companies have these issues and approach them in different ways. Rust is a very attractive approach for developers, since it’s just another programming language. It’s also quite ugly, people complain about its complexity and is unfortunately suffering from dependency explosion. I hope it’s a stepping stone to something better.
Comment by tialaramex 1 day ago
A "trade" implies care which isn't actually taken. What WG21 does is they assume that safety costs performance and so they throw away the safety hoping that this means they get performance. They don't measure, which is why you get to see first Herb Sutter explaining that C++ doesn't do bounds checks because they're unaffordable (notice he presents no data) and then a few years later Herb Sutter explaining that the latest C++ will offer bounds checks because they're actually affordable after all (now Google has collected the data)
In most cases it's much worse than the bounds checks, which actually did have a small cost, it's often net negative to throw away safety, C++ chose the less safe and slower option, assuming that this "trade" exists when it doesn't and if they'd measured they'd have seen the news before making the decision.
Comment by josephg 1 day ago
The borrow checker runs at compile-time, not run-time. Safety doesn't slow down your code except in a few small, specific ways like array bounds checks and UTF8 validity checking - but these checks also happen in unsafe rust too. The overhead is also mitigated by some of rust's other choices increasing performance. (For example, rust uses noalias everywhere, has larger codegen units by default and a better, faster standard library).
There was a really great analysis a few months ago looking at the performance impact of rust, C++ and hardened C++. They patched the compiler to see what happened when all runtime safety aspects were removed - and the result was about a 2-3% improvement. Measurable for sure, but nothing to write home about.
https://github.com/yugr/rust-slides/blob/ae3f5cc12d49e61f8f6...
> Secondly, Android C++ code is not particularly high quality, [..] Thirdly, it has a massive target on its back and is under attack by pretty much everyone.
Most code isn't particularly high quality. But I suspect google has better resources and processes than most C++ dev teams. As for security - just about all code is a target now that LLMs can find vulnerabilities so easily. I want all the software on my computer to be hardened against attacks that can be found and exploited in under $5 of compute.
> [Rust is] also quite ugly, people complain about its complexity and is unfortunately suffering from dependency explosion. I hope it’s a stepping stone to something better.
As Stroustrup once said, "There are only two kinds of languages: the ones people complain about and the ones nobody uses." It's a good sign that people are complaining about it. But otherwise I agree - I look forward to seeing how rust's borrow checker inspires new languages going forward. There's a lot more good ideas in the programming language space that we haven't scratched.
Comment by steveklabnik 1 day ago
You can see comments on /r/cpp here: https://www.reddit.com/r/cpp/comments/1tgtllt/bjarne_stroust...
There is a significant discussion about it.
However, there are also a number of other threads on /r/cpp where you can read about people's opinions. https://www.reddit.com/r/cpp/comments/1rsmw5j/c26_safety_fea... is one sort of recent (three months ago) thread that I remember having quite the discussion.
My take (which is, given that I worked on Rust, a bit biased, but I intend to be truthful regardless) is that there are some folks who agree with Bjarne, but also many who do not.
Time will tell.
Comment by saghm 1 day ago
I'll believe this when he can actually point to non-trivial, real-world C++ codebases that have managed to avoid having memory unsafety following these techniques. "It's technically possible for this issue to be avoided" is a lot easier to say than it is to actually make work in practice.
If Apple and friends have a secret recipe for avoiding C++ memory vulnerabilities, maybe they should start using it to avoid stuff like this: https://nvd.nist.gov/vuln/detail/CVE-2026-20700
Comment by pjmlp 20 hours ago
See Meet with Apple, security event.
Naturally they aren't going to throw away LLVM, DriverKit or Metal Shading Language, so there is a compromise there.
Comment by saghm 20 hours ago
Comment by pjmlp 18 hours ago
Dennis Ritchie had this to say about C,
> Although the first edition of K&R described most of the rules that brought C's type structure to its present form, many programs written in the older, more relaxed style persisted, and so did compilers that tolerated it. To encourage people to pay more attention to the official language rules, to detect legal but suspicious constructions, and to help find interface mismatches undetectable with simple mechanisms for separate compilation, Steve Johnson adapted his pcc compiler to produce lint [Johnson 79b], which scanned a set of files and remarked on dubious constructions.
So lint aka static analysis, exists since 1979, and yet in 2026 one still has to advocate for stuff like clang tidy to be used.
Now you can argue that the right way would be to fix the language, not outsource to a linter, yes although the same could be told about clippy versus improving Rust.
Just like even though C++ frameworks always had the option to have bounds checking enabled, it took until C++26, under industry and government pressure, to make it officially part of the standard.
Community culture is a big deal, and hence why you don't see everyone using unsafe (or similar) all over the place in memory safe languages, and it is a big deal to even improve C and C++ safety by at least adopt the tooling that is already there.
Comment by tialaramex 18 hours ago
About twelve months ago, Bjarne wrote a paper named "21st Century C++" for WG21. In that paper Bjarne begins with a 10 line C++ listing which he says is equivalent to a fairly trivial awk program. It's a needlessly bad program which in fact has Undefined Behaviour, as I pointed out here (on HN) at the time.
So when Bjarne says he hasn't had this problem, you can take that one of these ways:
1. Bjarne doesn't understand that "this problem" includes all UB, meaning he is grossly incompetent, you should disregard his opinion about this stuff.
2. Bjarne is deliberately lying to you, he knows he still has this problem but for whatever reason he wants you to believe he fixed it. You should disregard his opinion about this stuff.
3. Bjarne is too ignorant to even recognise that his program has UB, once again you should disregard his opinion about this stuff.
Comment by chilljinx 1 day ago
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-...
Comment by sunshowers 1 day ago
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).
Comment by aapoalas 1 day ago
Comment by sunshowers 1 day ago
Comment by sunshowers 16 hours ago
Comment by reallyinchaos 1 day ago
Comment by sunshowers 1 day ago
Comment by reallyinchaos 1 day ago
Comment by Groxx 1 day ago
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).
Comment by IcyWindows 1 day ago
Comment by chilljinx 1 day ago
Comment by fluffybucktsnek 1 day ago
Comment by afdbcreid 1 day ago
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.
Comment by chilljinx 1 day ago
Comment by pitaj 1 day ago
Comment by rumblefrog 1 day ago
Comment by afdbcreid 1 day ago
Comment by kllrnohj 1 day ago
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.
Comment by afdbcreid 1 day ago
Comment by Groxx 1 day ago
Comment by kllrnohj 1 day ago
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.
Comment by Groxx 1 day ago
As a starter / refresher perhaps, both of these are perfectly permissible and happen in practice with UB, but never with "wrap or panic" / "implementation defined" behavior: https://mohitmv.github.io/blog/Shocking-Undefined-Behaviour-... This kind of thing is an example of the "time travel" stevekablanik is referring to, stuff that is literally impossible as written, that absolutely no human would consider to be a reasonable execution of the code, but occurs regularly with UB.
Comment by kllrnohj 1 day ago
I don't know if Rust will ever attempt to fix this mistake, but I seriously hope they do.
Comment by afdbcreid 12 hours ago
In Rust the standard mandates a guaranteed wrap-around or a controlled crash. The default behavior is crashing in debug mode and wrapping-around in release mode, but you can control that with a compiler flag.
No matter how you look at it, the Rust behavior is safer. The default behavior? Way better in Rust than in C++. Want a guaranteed wrap-around? In Rust, check. In C++, depending on the compiler. Want a guaranteed crash? In Rust, check. In C++, depending on the compiler.
Also worth noting that overflowing has much more severe consequences in C++ than in Rust, due to bounds checks.
> I don't know if Rust will ever attempt to fix this mistake
It was discussed many times, and the conclusion is: it is too expensive, and the default will only change if that will change (due to better optimizations and/or better hardware). It is not a mistake, but a conscious decision.
Comment by Groxx 12 hours ago
> It was discussed many times, and the conclusion is: it is too expensive, and the default will only change if that will change (due to better optimizations and/or better hardware). It is not a mistake, but a conscious decision.
There's also wrapping_add / saturating_add for anyone concerned about this. Ya want a specific behavior? Just tell the compiler! You can also use the type wrappers so it happens implicitly! https://doc.rust-lang.org/std/num/struct.Saturating.html (presumably this is optimizable on hardware that has operators for this, but idk if that happens yet)
Comment by steveklabnik 1 day ago
rustc -C overflow-checks=yes
or in your project config, [profile.release]
overflow-checks = true
gives you consistent panics on overflow.Comment by steveklabnik 1 day ago
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."
Comment by Dylan16807 1 day ago
The default behavior helps you avoid wrapping without permanently bogging down your performance. It makes sense as an option.
Comment by chilljinx 1 day ago
Comment by slopinthebag 1 day ago
Am I missing something?
Comment by ankitpsaraogi 1 day ago
Comment by ashish296 1 day ago
Comment by fweimer 1 day ago
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.
Comment by afdbcreid 1 day ago
> 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.
Comment by tialaramex 1 day ago
The LLVM provenance bug is a really nice example. The Rust which tickles this bug (LLVM emits nonsense, claiming that two integers a and b are different but then calculating that a - b == 0...) is fairly clear, you wouldn't write it by accident but it's obvious what it should do, and unsettling to discover that the bug isn't in Rust's compiler frontend but in LLVM.
You can write equivalent C or C++ to show the bug with Clang - but when you try to write it you'll struggle, not to reproduce the bug per se, but to stop writing Undefined Behaviour, which invalidates your bug report because the LLVM devs will say "This is UB, working as intended". The non-UB reproducers are much more elaborate than the safe Rust was.
Comment by bannable 1 day ago
Comment by tialaramex 1 day ago
Are you familiar with pointer provenance ? This gets very deep, very fast, so if you don't know and don't want to know I can't help you, but if you do want to know try maybe: https://www.ralfj.de/blog/2018/07/24/pointers-and-bytes.html
So e.g. if we make a pointer to thing A, which we then destroy, and then for a pointer to thing B, and then we compare these pointers, even if the address which will be the only bits making up this pointer in hardware was identical, a language could choose to say these pointers are not the same (Rust says they compare equal but that's up to Rust). LLVM is equipped to do this optimisation. So far, not a bug, though perhaps not what you expected...
However everybody is pretty sure that we don't want provenance for other value types. It's troublesome for pointers but we're used to it and it unlocks important optimisations, but for every other value type it's just extra trouble. So Rust's provenance model says only pointers have provenance, and proposals for C and C++ likewise. If we ask for the address from a pointer, making it into just an integer, it should not longer have provenance.
But, LLVM doesn't really track whether a value "is" pointer or not per se, so it ends up applying that "they're not equal" optimisation to the integers we've made from pointers, even though the integers are definitely equal and we're about to do a subtraction to prove it. Bang.
Comment by dralley 1 day ago
I mean, this is basically true. And it goes beyond type safety - there have been CVEs filed against the Rust stdlib for TOCTOU problems of a kind that the C++ stdlib is absolutely replete with (often the exact same ones in the exact same places, to the extent that comparable APIs exist) which ended up being fixed quickly in Rust and largely ignored in C++, if anyone bothered to file in the first place.
For sure does create headaches for those who need to categorize CVEs by impact, but on balance I don't think it's a bad thing for the ecosystem. Creating a culture that wants to fix soundness issues rather than mark them as WONTFIX with a line of documentation is a core principle and value proposition of Rust in the first place.
Quoting https://cor3ntin.github.io/posts/safety/
> But the borrow checker is not what makes Rust safe. Rust is safe because it decides to put correctness first by default.
> Rust is safe by culture.
Better to pay a penny to fix it today than a pound to deal with the fallout down the line.
Comment by jurschreuder 1 day ago
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.
Comment by khuey 1 day ago
Unless your point is merely that average Joes write such terrible code that you don't even need memory safety issues to exploit their software, [citation needed]
Google says memory safety issues are 75% of exploited zero days. (https://security.googleblog.com/2024/10/safer-with-google-ad...)
Comment by kalaksi 1 day ago
Comment by jurschreuder 13 hours ago
Comment by wahern 1 day ago
Which isn't to say Rust wouldn't have caught many of the other memory safety issues, but 75% is horribly misleading.
Comment by jurschreuder 13 hours ago
Comment by afdbcreid 1 day ago
Which is... true? but irrelevant. Such applications are not suggested to be ported to Rust. Of course, some people still do that, because they like Rust; but that's their personal choice.
Comment by jurschreuder 13 hours ago
Comment by fragmede 12 hours ago
Comment by bbippin 1 day ago
For a language as ugly as Rust, my thought is that people should actually be using Ada, and have a mathematically provable correctness angle; not just a replacement for C/C++ with memory safety.
Comment by khuey 1 day ago
If memory safety issues are 75% of exploited zero days it sounds to me like they're the biggest issue in the ecosystem by far.
Comment by jurschreuder 13 hours ago
Comment by bbippin 1 day ago
Most exploited code probably exists in the application layer in a high-level, memory safe language. I would wager that but I don’t have time to cite ten papers on HN.
Comment by jabl 1 day ago
It's a bit like saying you should program in C, because formal verification tool X generates C code hence C is safe.
Comment by afdbcreid 1 day ago
Comment by bbippin 1 day ago
I think formal verification is the way to go with AI moving forward.
Comment by sunshowers 1 day ago
Comment by jurschreuder 13 hours ago
Comment by jeffbee 1 day ago
Comment by jurschreuder 13 hours ago
But no developers working on projects that have been so ultimately battle tested that only memory safety issues remain do that. Professional C++ developers use RAII and containers. If you use raw pointers or raw arrays in C++ you will get 200 code reviewers lecturing you. You will never be able to for long.
Comment by nulltrace 1 day ago
Comment by pengaru 1 day ago
how old are you?
Comment by slopinthebag 1 day ago
Comment by jurschreuder 13 hours ago
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.
Comment by Sohcahtoa82 1 day ago
Comment by lawn 1 day ago
Comment by chilljinx 1 day ago
The borrow checker does add something, but it definitely costs something as well in multiple ways, also in terms of how it is done in Rust and at a programming language design perspective.
It would be very funny if you were batting for Rust, and just having a laugh at others here.