Rendered at 04:22:16 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
john_strinlai 10 hours 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)
mk89 8 hours ago [-]
Oh no, you're in for a surprise.
"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.
jamesfinlayson 4 hours ago [-]
Yep, at work my team's vulnerability dashboard constantly shows hundreds of critical and high vulnerabilities. Fortunately/unfortunately, 99% of these issues are for Javascript dependencies in websites that are not server-side rendered... so we look bad, even though we have no exposure to most of these vulnerabilities.
tptacek 3 hours ago [-]
Compliance != security. It's almost the natural enemy of security.
john_strinlai 8 hours ago [-]
>all these infosec folks
i am an infosec folk (:
mk89 4 hours ago [-]
Well you're a bit different then...
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.
cfdryhh 6 hours ago [-]
[flagged]
kkishahva 7 hours ago [-]
[flagged]
mswphd 7 hours ago [-]
interesting 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.
isuguahs 6 hours ago [-]
[flagged]
isurug7wu 6 hours ago [-]
[flagged]
dtornabene 7 hours ago [-]
yeah this is absurd and a brand new account pushing it too.
kwveddlsjggej 1 hours ago [-]
They'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.
cesaref 10 hours ago [-]
Is 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 10 hours ago [-]
If 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 9 hours ago [-]
It'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 6 hours ago [-]
That is exactly why you have a precondition or assertion.
If everyone expects specific behavior - ie it’s in the contract - you require that contract.
lathiat 3 hours ago [-]
The problem with asserts is that they are pretty dramatic and you crash the entire program.
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.
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...
josephg 3 hours ago [-]
Returning to the context of this post, this is one of the things I really like about rust. (And zig, haskell, typescript, swift and others). These languages make invalid states impossible to represent. If my function takes a value of type T (or &T), you can't accidentally receive NULL. So you just don't need to worry about this stuff any more. The compiler simply won't compile the program if type checking fails. At runtime, I only have to consider valid values.
hathawsh 6 hours ago [-]
Yes, 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.
dwattttt 6 hours ago [-]
An assertion is an app crashing on a violation. The problem is when it's not guaranteed to crash, and instead does something very wrong.
jstimpfle 5 hours ago [-]
A bug is a bug even when it doesn't clearly manifest itself 100% of the time, and furthermore it is pretty much guaranteed that NULL dereference crashes with segfault in practice, only not for the people playing theoretic games whose essence of life is finding gotchas where it maybe isn't so and then feeling smarter than everyone else.
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.
lmm 3 hours ago [-]
> it's >> 99.9% true that this will just crash even though it's acshually UB, nasal demons and so forth.
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.
Dylan16807 5 hours ago [-]
I don't want to nitpick people often but your use of division sign to mean percent is really throwing me off.
jstimpfle 5 hours ago [-]
Thanks for letting me know, nitpick appreciated. Typing on my phone.
asveikau 3 hours ago [-]
An assert is not guaranteed to terminate the process. In C, the most common implementation choice is to completely omit the check if you're not building in debug mode.
gkfasdfasdf 7 hours ago [-]
In addition to an assert, a 'nonnull' attribute on compilers that support it seems like a good idea.
blueg3 4 hours ago [-]
If you use the nonnull attribute, the assertion will be optimized away.
bawolff 9 hours ago [-]
I'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 9 hours ago [-]
Ye, 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 7 hours 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.
tialaramex 8 hours ago [-]
But it isn't different, that's Tony Hoare's Billion Dollar Mistake.
__s 7 hours ago [-]
It's absolutely different: “I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.”
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
tialaramex 7 hours ago [-]
My contrast was to "That feels quite a bit different". The type system in C only has Tony's nullable references, you can't say that you don't mean that because it wasn't your choice to make, it's like if some C programmers say obviously they don't mean zero when they take an integer - too bad, C doesn't have the non-zero integers (Rust does, NonZeroI32 for example is the signed 32-bit integers except zero)
selfmodruntime 6 hours ago [-]
It is different. Handling `None` in a way that crashes your program is well defined in a Rust function. If you're using `unwrap` or `expect`, the program will crash with a stack trace and an error, instead of running into undefined behavior.
josephg 2 hours ago [-]
Yes. Its also explicit instead of implicit. In rust (and typescript, swift, haskell and others), you have to opt-in to nullability. By default, functions can't take a null in place of a non-nullable value. And whether a function accepts a T or an Option<T> is part of the signature.
7 hours ago [-]
bitbasher 9 hours ago [-]
Memory 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.
insanitybit 1 hours ago [-]
It's not a trade. It isn't "because we got memory safety we have to lose supply chain security". Rust, like every other language, has put minimal preemptive effort into supply chain security. There's recently basic stuff like Trusted Publishing and dependency cooldowns are on the way, but that's it in terms of native features - nothing novel or special, really.
Thankfully the community has built `cargo-vet`, which is basically a best-in-class distributed auditing system.
anuramat 8 hours ago [-]
> supply chain risk
how is rust special in this regard?
bitbasher 8 hours ago [-]
Rust's standard library is incredibly thin (intentionally so). As a result, you need to use the crate ecosystem. This comes with some downsides.
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...
okanat 5 hours ago [-]
> Rust's standard library is incredibly thin (intentionally so). As a result, you need to use the crate ecosystem. This comes with some downsides.
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.
armitron 57 minutes ago [-]
I've never seen a C program use hundreds of dependencies. This is typical in Rust (and Node). I know a few high assurance teams that dropped Rust for this very reason.
I've seen it, but it's from 2016. They have known about the issue for a 10+ years and haven't fixed it yet... seems unlikely to change!
Maybe some day though!
dochtman 8 hours ago [-]
> I wonder if someone could create a GitHub account using my name and claim ownership of them...
AIUI the crates are actually linked to the account via a different identifier, not directly to the username.
anuramat 7 hours ago [-]
again, I don't really see how 1 and 2 are rust specific; compared to c -- sure, but it's seems unfair: the type of rust software that needs a bunch of random dependencies usually wouldn't even exist in c in the first place; if it would, then it's more of a software quality problem than security
even 4 -- fuck microsoft of course, but other than that: you always need some sort of an account to publish stuff
tcfhgj 8 hours ago [-]
I think none of this is special to Rust vs C++, except #4, because C++ doesn't have an equivalent
bitbasher 7 hours ago [-]
Most dependencies in the C/C++ world come with fewer dependencies of their own (at least, an order of magnitude fewer than the average rust dependency).
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.
dralley 5 hours ago [-]
But how often do people just copy and paste code in the C/C++ ecosystem? Or reimplement things badly? Last I checked VLC had a homegrown XML parser.
armitron 54 minutes ago [-]
Experts know that copy/pasting and/or reimplementing code is not an issue in practice regardless of how often it comes up as an anti-pattern in freshman CS courses. The (amalgamated) software system can still be audited in reasonable time as long as the number of third party dependencies is kept low.
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.
galangalalgol 8 hours ago [-]
In 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 8 hours ago [-]
> austral
thanks, can't believe the idea isn't more mainstream -- I've never thought dependency safety could be a thing
galangalalgol 7 hours ago [-]
In 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.
selfmodruntime 6 hours ago [-]
It really isn't and AFAIK there has been little if any supply chain compromise in Rust code as of now
dundarious 4 hours ago [-]
It's not special in this regard in the language, or even especially so in the available tooling. Nevertheless, the culture in rust is to add many many dependencies. I occasionally use self-professed "small, modern" CLI tools that use ~400 crates (e.g., interactive podcast downloader).
shevy-java 11 hours ago [-]
C 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):
"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.
ghosty141 10 hours 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 10 hours ago [-]
A 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 3 hours 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."
360MustangScope 10 hours ago [-]
I agree about Rust gaining ground but using the argument that it got 10% faster due to Rust is not really that useful.
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.
cogman10 10 hours ago [-]
I think the difference in languages that allows for faster performance is that Rust does a good job of surfacing expensive operations and it makes defensive programming less of a requirement.
tialaramex 10 hours 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.
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.
tick_tock_tick 7 hours ago [-]
Until Rust has equal meta-programming support to C++ it's always going to be "slower". That's why people always say this because it's always true there is nothing Rust can do C++ can't but there is quite a few things you can do in C++ but not in Rust.
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.
josephg 2 hours ago [-]
> Until Rust has equal meta-programming support to C++ it's always going to be "slower".
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.
> Until Rust has equal meta-programming support to C++ it's always going to be "slower".
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.
tick_tock_tick 2 hours ago [-]
No one writing anything that needs performance cares about some standard library ABI issues. Rust already has warts from bad API designs that constrains performance and they are unlikely to ever be fixed even with new editions. Rust will continue to pick up baggage as basically every language has done.
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.
josephg 2 hours ago [-]
> Rust already has warts from bad API designs that constrains performance and they are unlikely to ever be fixed even with new editions.
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?
11 hours ago [-]
FpUser 10 hours ago [-]
>"are kind of losing out to Rust right now"
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
reallyinchaos 10 hours ago [-]
[dead]
vouwfietsman 10 hours ago [-]
Knowing little about cpp modules and nothing about Gabriel Dos Reis, I expect a more design-by-committee type explanation for the result: the module system was probably a victim of having to be backwards compatible, abi stable, idiomatic, zero cost abstraction, be compatible with all weird cpp features, not hurt compile time, etc etc etc
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.
reallyinchaos 10 hours ago [-]
[flagged]
jooops1 10 hours ago [-]
Yep I agree C++ lacks many features Rust has solid support for. But the real issue with C++ is the development process, almost all the people involved in the Module system are rather old and worked for Microsoft once. They are just in their own bubble and not having an open RFC-process blocks experts in that field.
thegrim33 9 hours ago [-]
Really 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.
okanat 7 hours ago [-]
I'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?
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.
afdbcreid 8 hours ago [-]
This 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.
Decabytes 7 hours ago [-]
Bjarne Stroustrup was recently interviewed by Ryan Peterman^1
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
josephg 2 hours ago [-]
If these hardened libraries were as good, we wouldn't have blog posts like this[1], from the android team last year.
> 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.
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.
ankitpsaraogi 9 hours ago [-]
[flagged]
chilljinx 11 hours ago [-]
Unsafe 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.
If 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
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).
aapoalas 9 hours ago [-]
Ooh, 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 8 hours ago [-]
Mostly chatted with some people and figured it out with their help.
reallyinchaos 10 hours ago [-]
[flagged]
sunshowers 10 hours ago [-]
I'm a huge fan of Rust! I like to think my writing makes the Rust community better more than it annoys people :)
reallyinchaos 10 hours ago [-]
[dead]
Groxx 11 hours ago [-]
I'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).
IcyWindows 5 hours ago [-]
I 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"
chilljinx 11 hours ago [-]
[flagged]
fluffybucktsnek 9 hours ago [-]
No, they are asking for clarification.
kllrnohj 11 hours 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.
afdbcreid 11 hours ago [-]
You 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.
No, 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.
Groxx 8 hours ago [-]
It's surprising and potentially buggy behavior, but that's very different from undefined behavior. To such a degree that I think you honestly might not understand what it means, and what the risks are around undefined behavior, especially in the presence of an optimizing compiler.
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.
kllrnohj 2 hours ago [-]
-fsantize=integer and whambo bambo C/C++'s "time traveling UB" is now more consistent, better defined, and safer than Rust's release build behavior.
I don't know if Rust will ever attempt to fix this mistake, but I seriously hope they do.
steveklabnik 2 hours ago [-]
If you're talking about compiler flags,
rustc -C overflow-checks=yes
or in your project config,
[profile.release]
overflow-checks = true
gives you consistent panics on overflow.
steveklabnik 9 hours 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 9 hours ago [-]
If 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.
chilljinx 11 hours ago [-]
Which 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 11 hours 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.
chilljinx 11 hours ago [-]
[flagged]
pitaj 11 hours ago [-]
Explain how it is relevant
rumblefrog 10 hours ago [-]
Little hostile with the refutal
afdbcreid 11 hours ago [-]
What? Absolutely not. May you explain why no_std is relevant?
slopinthebag 11 hours ago [-]
> The fix for this bug is included in Rust 1.87.0
Am I missing something?
ashish296 12 hours ago [-]
[flagged]
fweimer 10 hours ago [-]
I'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 10 hours ago [-]
You 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.
tialaramex 9 hours ago [-]
> 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.
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.
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.
dralley 10 hours ago [-]
>Otherwise, it does not bode well for Rust code because any type safety glitch will be considered a vulnerability.
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.
> 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.
jurschreuder 11 hours ago [-]
Just 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.
khuey 11 hours ago [-]
> Just want to remind everyone that only 1% of vulnerabilities are memory related in the average Joe's code.
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]
Most memory bugs in Chromium are in V8, either entirely in the JIT or at the boundary with C++. Rust wouldn't help here because the borrow checker can't see through these boundaries, and it's precisely this opacity where the developers also lose track of things.
Which isn't to say Rust wouldn't have caught many of the other memory safety issues, but 75% is horribly misleading.
afdbcreid 10 hours ago [-]
My understanding is that they claim that the average Joe writes code in a garbage-collected memory-safe language.
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.
bbippin 11 hours ago [-]
The point is that memory issues are a smallish number of issue compared to the larger ecosystem of vulnerabilities, and choosing to port everything to Rust is like over-optimizing. Well, that’s my 2 cents.
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.
khuey 10 hours ago [-]
> The point is that memory issues are a smallish number of issue compared to the larger ecosystem of vulnerabilities
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.
bbippin 9 hours ago [-]
Perhaps. But what percentage of exploits are actually zero days versus, say, 10 days or 100 days?
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.
jabl 10 hours ago [-]
Rust and Ada are about equally safe, both have advantages and disadvantages. Perhaps you're thinking about SPARK ADA, but that's a different kettle of fish.
It's a bit like saying you should program in C, because formal verification tool X generates C code hence C is safe.
bbippin 9 hours ago [-]
Yeah SPARK ADA is what I meant :)
I think formal verification is the way to go with AI moving forward.
afdbcreid 9 hours ago [-]
Rust and non-SPARK Ada are not equally safe. Ada is unsafe in the presence of data races, and also has runtime checks that slow it down, or you disable them and then it's even less safe.
sunshowers 9 hours ago [-]
Rust is a beautiful language. Gorgeous.
jeffbee 11 hours ago [-]
Hrmm. I don't think there exists a set of compiler flags that will just make an existing C++ (or, worse, a mixed C and C++) project safe to the extent that you suggested. The STL hardening flags don't help for ordinary arrays that aren't accessed via smart pointers, and they don't help code that uses a pointer+offset style of access. As for UAF, nothing in C++ comprehensively prevents you from accessing an invalid stored reference even if you have cranked up the hardening mode to DEBUG. Rust, on the other hand, affirmatively prevents that.
I do not believe that I agree, and I am not sure about all of your numbers.
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.
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)
"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.
i am an infosec folk (:
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.
> 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.
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.
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.
If everyone expects specific behavior - ie it’s in the contract - you require that contract.
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...
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.
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.
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
However, Rust seems to trade memory safety vulnerabilities for supply chain risk.
Thankfully the community has built `cargo-vet`, which is basically a best-in-class distributed auditing system.
how is rust special in this regard?
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...
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.
Maybe some day though!
AIUI the crates are actually linked to the account via a different identifier, not directly to the username.
even 4 -- fuck microsoft of course, but other than that: you always need some sort of an account to publish stuff
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.
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.
thanks, can't believe the idea isn't more mainstream -- I've never thought dependency safety could be a thing
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.
I think it's also a big sign that the linux kernel adopted rust and not c++. (only for small parts but still)
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.
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."
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.
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.
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.
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
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.
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.
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?
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
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.
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.
And there are plenty of ways to cause UB with modern C++ idioms.
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
> 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...
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.
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-...
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).
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).
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.
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.
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.
I don't know if Rust will ever attempt to fix this mistake, but I seriously hope they do.
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."
The default behavior helps you avoid wrapping without permanently bogging down your performance. It makes sense as an option.
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.
Am I missing something?
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.
> 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.
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.
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.
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.
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.
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...)
Which isn't to say Rust wouldn't have caught many of the other memory safety issues, but 75% is horribly misleading.
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.
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.
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.
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.
It's a bit like saying you should program in C, because formal verification tool X generates C code hence C is safe.
I think formal verification is the way to go with AI moving forward.
how old are you?
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.