Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • 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.

    UB in both user library and standard library:

    https://materialize.com/blog/rust-concurrency-bug-unbounded-...

  • > The fix for this bug is included in Rust 1.87.0

    Am I missing something?

  • > 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.

  • > 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.

  • 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).

  • 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).

  • Bjarne Stroustrup was recently interviewed by Ryan Peterman^1

    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

  • > I haven't had those problems for years

    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.

  • > 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'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

  • > I'm not a C++ guy, so how much of this is true?

    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.

  • 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.

    [1] https://blog.google/security/rust-in-android-move-fast-fix-t...

  • 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.
  • Because that is how the real world works, regardless of many of us get annoyed to have people coding in C with C++ compilers.

    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.

  • 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.

  • This doesn't change a thing, because Rust is an answer to Modern C++ still being inherently unsafe and not meeting the bar. The best that C++26 has to offer is below the basic guarantees that Rust shipped in 2015.

    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.

  • 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?

    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.

  • 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.

  • > supply chain risk

    how is rust special in this regard?

  • 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.

  • 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.
  • But it isn't different, that's Tony Hoare's Billion Dollar Mistake.
  • 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.
  • There can be made very good arguments why C is less safe than Rust, but null pointer dereferences which are perfectly safe everywhere except on weird platforms (and usually could be made safe even there by turning on a compiler flag) seems a very misleading argument.

    And as as the Cloudflare incident showed, a Rust unwrap can have equally bad consequences. (or as Ariane 5 showed, a safe overflow in Ada can have explosive consequences)

  • > And as as the Cloudflare incident showed, a Rust unwrap can have equally bad consequences.

    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.

    by Ygg2
  • These Rust discussions typically contain grains of truth wrapped into exaggerations while downplaying or ignoring the two big issues of Rust, which are complexity and out of control dependency trees.

    For the first issue of complexity, the reply is along the lines of show me the code and then either nitpicking that to pieces or explaining in several paragraphs how the behavior is perfectly reasonable and in fact quite easy to understand. Beginners get intimidated, professionals don’t have time to write novels on HN. Complexity in Rust is systemic. It’s little things accumulating and amplifying each-other that add up to having to spend significant time just designing types to satisfy the static analyzer. Many Rust programmers seem to see the type system as a hammer to be used liberally, an predilection also known in the C++ metaprogramming community.

    On the second topic (also present in this thread) the counter-argument is that other languages do it too and nothing bad happened so far. The former is not valid, because Rust is uniquely bad in its competitor group and security by waiting is not a valued approach.

    by blub
  • A dereference in the final binary is not different from Rust. A dereference in the source code, that makes the whole program invalid, so the compiler doesn't emit a credentials check you wanted it to emit, is.

    For availability and stability concerns, the C approach is actually better, but for security and reproducibility, it is not.

  • 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.

  • In addition to an assert, a 'nonnull' attribute on compilers that support it seems like a good idea.
  • > it's not possible to add a precondition without introducing a runtime overhead

    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.

  • 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.