22 ms·
C++ Safety, in Context
- sirwhinesalot 3y agoI saddens me that smart people like Herb and Bjarne have good ideas on how to make C++ a much safer language but the actual output of the standard's committee is so far behind. Herb mentions std::span as as safety improvement but the [] operator doesn't do bounds checks and the .at() method isn't even there yet! Shameless plug but I discuss this issue on my blog: https://btmc.substack.com/p/memory-unsafety-is-an-attitude-problem https://btmc.substack.com/p/memory-unsafety-is-an-attitude-p... Herb and Bjarne have the right attitude, sadly it doesn't seem enough C++ devs or people in the standards committee do. Same applies to C.
- pjmlp 3y agoHere is Dennis Ritchie proposal for fat pointers in C. https://www.bell-labs.com/usr/dmr/www/vararray.pdf https://www.bell-labs.com/usr/dmr/www/vararray.pdf It is a culture thing, eventually the authors don't have any last words to say, if they let the community rule the language design, and their voice is equally one vote.
- sirwhinesalot 3y ago> This is a version of a paper published in Journal of C Language Translation, vol 2 number 2, September 1990 This says it all really. Nothing more needs to be said. Unfortunate.
- akoboldfrying 3y agoI haven't read the linked paper, but both CPU speed and RAM available have increased about 100x since 1990, and nobody then had uttered the words "threat model". Some approaches that are sensible now were reasonable to overlook in 1990 for being too heavy.
- sirwhinesalot 3y agoYes but the same story kept repeating over the years. C89 had a good excuse. C99 was iffy with the VLA stuff instead of proper slices. What excuse did C11 have?
- pjmlp 3y agoCheck when Morris worm came out. And by the way, "A consequence of this principle is that every occurrence of every subscript of every subscripted variable was on every occasion checked at run time against both the upper and the lower declared bounds of the array. Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to--they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980 language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law." -- C.A.R Hoare's "The 1980 ACM Turing Award Lecture"
- akoboldfrying 3y agoThe Morris worm affected around 2000 VAX machines a couple of years previously, and was the first ever such incident on that scale. In other words, almost nobody in 1990 had been affected by a computer security incident. It didn't make sense in 1990 to prioritise this security threat over efficiency concerns. Insisting on memory safety back then would be like insisting on code being accompanied by checkable formal proofs of correctness now: It's a technique that can be applied right now and that does improve safety, but it comes at such a cost that the tradeoff only makes sense for a handful of niche applications (aerospace, automotive, medical devices).
- pjmlp 3y agoYeah, that is why we didn't had to buy anti-virus software, duh.
- 3y ago
- GrumpySloth 3y agoAt $work, the standard solution to ASAN reporting use-after-free issues is to... not run ASAN builds. The fact that builds in CI exhibit random inexplicable crashes regularly every week doesn’t seem to make anyone have any second thoughts. A colleague once claimed that there is nothing wrong with out-of-bounds accesses as long as we don’t crash. The same bunch is also religiously opposed to using debuggers and regularly break debugger builds by removing debug information from builds at multiple levels, blocking ptrace debugging in system images through sysctl... This is all so toxic.
- sirwhinesalot 3y agoMy personal opinion is that if companies would get real punishments for all of these goddamn security breaches, and the CTO's head was on the line, you'd see a shift in attitude real quick.
- bluetomcat 3y agoNot all pieces of software are created equal. A desktop CAD application that doesn't do any networking and doesn't manipulate sensitive user data isn't worthy of binary exploitation. If there is adequate security at the system OS layer, at worst it will corrupt a user's file. Infrastructure network code that runs on millions of servers worldwide is a completely different story. Being able to send a sequence of bytes that unlocks funny side-effects of a network service can be weaponised on a mass scale.
- sirwhinesalot 3y agoThose are increasingly rare. Nowadays you have all these apps requiring subscriptions and expecting users to login and what not. But I agree it depends heavily on exactly what application are we talking about. Is it running on server? Definitely needs to be security conscious. Is it a library that might at some point be used by an application running on a server? Needs to be more hardened than a nuclear bunker.
- 3y ago
- gpderetta 3y agoEven if not mandated by the standard, concrete standard library implementations do provide bound checking on span (and vector, and optional, etc.), but, even when meant for production use, are disabled by default. And I don't see a big push in the community to enable them. I think the committee is just an expression of the community on this front.
- account42 3y ago> Even if not mandated by the standard, concrete standard library implementations do provide bound checking on span (and vector, and optional, etc.), but, even when meant for production use, are disabled by default. That's a choice though. You can enable these in your production builds if you want (with libstdc++ at least) and some Linux distributions have chosen to do just that. The thing though is that these checks are NOT free and the overhead is not justified for all use cases so forcing them on everyone is not appropriate for C++.
- gpderetta 3y ago> The thing though is that these checks are NOT free and the overhead is not justified for all use cases so forcing them on everyone is not appropriate for C++. Well, that's why they should be a flag. The question is whether it should be enabled by default or not.
- fanf2 3y agoIt should be enabled by default, and if you want to index without bounds checking you should have to write something like a.unsafe_at(i)
- jasode 3y ago> but the actual output of the standard's committee is so far behind. That criticism misunderstands the actual way the C++ committee works. They're not a supreme legislative group that can dictate what a new C++ should be and everybody else is required to just obey. In contrast, Apple can dictate what the next version Swift will do. Microsoft can do the same with C#. Instead, what happens in C++ is somebody or company makes a proposal with some concrete working code for others to evaluate and vote "yes" on. So the reality means one of the teams from MSVC, gcc, clang, Intel C++, etc have to take the lead with a Safe C++ alternative that convinces everybody else to implement. To Herb Sutter's credit, he did make a "C++2" implementation: https://github.com/hsutter/cppfront https://github.com/hsutter/cppfront But his side project at Microsoft didn't gain traction with gcc, clang, etc and everybody else in the industry. So at this point, the C++ committee will be perceived as "so far behind" ... because there's nothing for them to vote on. Similar situation happened with "breaking ABI compatibility". Google wants to break ABI but others didn't.
- pjmlp 3y agoAnd that is why while C++26 is being discussed, C++20 modules are still full of warts, working on Visual C++ (kind of), and not really anywhere else, as ISO C++ has long stop being about standardizing stuff with actual field experience.
- jasode 3y ago>And that is why [...] C++20 modules are still full of warts, working on Visual C++ (kind of), and not really anywhere else, as ISO C++ has long stop being about standardizing stuff with actual field experience. Yes, but your complaint about flawed C++ standards or incomplete implementations is orthogonal to what I was writing about. I'm just explaining that the C++ committee doesn't have the power to impose changes that some people think it does. Basically, I'm saying "the sky is blue" type of statement. The C++ committee is a reflection of what the members' compiler teams want to collectively do. The committee doesn't have unilateral supreme power to dictate standards to compiler teams not interested in it. Instead, they collect feedback from people sharing proposals in papers and put things to a vote. The compilers' teams have the real power and not the committee. (What I've stated in this paragraph should be uncontroversial facts but the downvoters disagree so I'd love to hear them explain exactly what power and agency they think the C++ committee actually has.) If one understand the above situation, then the following different situations shouldn't have any mystery as to cause & effect: - How did the std::chrono get added to the standard library? Because Howard Hinnant made a proposal with working code, and others liked it enough to vote it in. - Why is there's no _standard_ cross-platform GUI and audio library in C++? Why is there not standardized Safe Syntax C++ like Rust? Because nobody has made a proposal that convinced enough of the other members to agree to a x-platform GUI and audio framework. - Why does C++ committee adds features and prioritizes things I don't care about? Because the <$feature$> you cared about wasn't proposed for them to discuss and convince others enough to vote it in. But yes I do understand the "warts" complaint you're talking about. It's frustrating that the std:regex with bad performance got approved. In similar examples, N Josuttis in multiple conference videos has complained about the problems with ranges and views. He says it was wrong for the C++ committee to approve it. (footnote: The original author of the proposal tried to explain his technical rationale: https://old.reddit.com/r/cpp/comments/zq2xdi/are_there_likely_to_be_any_changes_to_views_to/ https://old.reddit.com/r/cpp/comments/zq2xdi/are_there_likel... ) To reiterate, I'm not trying to explain away bad language standards. New features that will have flaws will continue to happen in the future whether it's created by a singular corporation like Apple(Swift) or a cooperative group like the C++ committee. I'm just explaining why some "wishlist desirable C++ feature" isn't going to be in the standard if there's no proposal that convinces the other members to vote it in. EDIT to reply: >When we complain about the "committee" [...] the things they choose to propose and vote for. The C++ committee members are not static but the webpage has list of names : https://isocpp.org/wiki/faq/wg21 https://isocpp.org/wiki/faq/wg21 Clicking on various PnnnnR.pdf proposals that motivated each feature in the conformance table shows most authors are not from the actual committee members: https://en.cppreference.com/w/cpp/compiler_support https://en.cppreference.com/w/cpp/compiler_support Using the above workflow to address your complaint about std::span and at(), I found this comment from the original author Tristan Brindle who proposed it and why he thinks the committee voted no: 2019-10-18T22:55:30z https://old.reddit.com/r/cpp/comments/djqdu2/why_is_stdspan_is_missing_at/f48hhb5/ https://old.reddit.com/r/cpp/comments/djqdu2/why_is_stdspan_...
- humanrebar 3y ago> ...the actual output of the standard's committee is so far behind The committee just publishes documents. It is actually far ahead of C++ implementations. The committee would probably move faster if there were more attention (and funds and volunteer work) spent on advancing C++ implementations. This especially seems true for safety and security concerns as they tend to have more tangible problems to solve than the other kinds of standards proposals.
- sirwhinesalot 3y agoYou're not far ahead if you're running in the wrong direction. The standard is prioritizing the wrong things. It's normal that implementations are struggling when they need to implement something as complicated as C++ modules for example. There's no excuse for the .at() method being missing from std::span. On the C side of things the problem is more egregious, it took over 30 years to standardize typeof after every compiler ever had already implemented something of the sort. GCC's __attribute__((cleanup)) should have definitely been standardized ages ago with so many libraries and codebases relying on it. What does the C standard give us instead? _Generic. It's just silly at this point.
- gpderetta 3y ago> There's no excuse for the .at() method being missing from std::span. The issue is that there are two camps. One believes that precondition failures should not be recoverable and should abort the application and thus think that 'at' is an abomination. The other believes that throwing exceptions on the face of precondition failure is appropriate. Hence what goes into the standard depends on how many people on each camp are present at each committee vote. This is also one of the reasons why the contracts proposal is not yet in the standard. On a more practical side, .at does not help in any way to bound check the hundreds of billions of existing lines of C++.
- sirwhinesalot 3y agostd::span came out in C++20, by that logic neither did it help in any way... Personally operator [] should abort by default because otherwise it is redundant with .at()
- stefanos82 3y ago> Herb mentions std::span as as safety improvement but the [] operator doesn't do bounds checks and the .at() method isn't even there yet! You mean this implementation? https://en.cppreference.com/w/cpp/container/span/at https://en.cppreference.com/w/cpp/container/span/at To quote: "Returns a reference to the element at specified location pos, with bounds checking. If pos is not within the range of the span, an exception of type std::out_of_range is thrown."
- pjmlp 3y agoYou missed the Std column => (C++26)
- AlbertoGP 3y ago> Shameless plug but I discuss this issue on my blog: > “First make them care, then make it easy for them to do the right thing.” I would say first make it easy to do the right thing, making them care will be an Eternal September.
- sirwhinesalot 3y agoSadly even if you make it easy to do the right thing, without the right attitude to match it matters little. Some people still concatenate unsanitized input with raw SQL strings despite the abundance of libraries that make creating safe queries easier. At this point I think heads need to roll before people take the problem seriously.
- AlbertoGP 3y agoI wasn’t clear: we do agree that attitude is the crucial piece, I just disagreed on the order in which it should be done. I think that implementing in compilers the mechanisms for doing the right thing can be done first, and relatively quickly. Which now that I think more about it, would need the right attitude on the part of the compiler vendors and standards committee.
- pptr 3y agoBeing able to use a foreach loops is a decent improvement. And since you now have a proper access API, you could on theory enable bounds checks via compiler flag, even for operator[].
- nindalf 3y ago> All languages have CVEs, C++ just has more (and C still more); so far in 2024, Rust has 6 CVEs [1], and C and C++ combined have 61 CVEs [2]. So zero isn’t the goal; something like a 90% reduction is necessary, and a 98% reduction is sufficient, to achieve security parity with the levels of language safety provided by MSLs The author is making a massive assumption that all CVEs are equally serious but they aren't. Opening the Rust links indicates several of them are denial of service, including regular expression denial of service. Not downplaying this, but compare it to the first result in the other link, which involves potential remote code execution (RCE). Take for example CVE-2022-21658 (https://blog.rust-lang.org/2022/01/20/cve-2022-21658.html https://blog.rust-lang.org/2022/01/20/cve-2022-21658.html) in Rust, related to a filesystem API. It's true, this was a CVE in Rust and not a CVE in C++, but only because C++ doesn't regard the issue as a problem at all. The problem definitely exists in C++, but it's not acknowledged as a problem, let alone fixed. That's why counting CVEs alone is meaningless. The author concedes that CVEs are not a good metric to measure by, but implies that maybe C and C++ have too many CVEs that shouldn't actually be CVEs and that the C++ community should take more control of CVEs being filed. This is ominous, and makes me fear we might start to see fewer C and C++ CVEs because issues will be closed as "intended behaviour" or "won't fix", like the filesystem issue above. [1] - https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=rust https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=rust [2] - https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=c++ https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=c++
- criddell 3y agoHis 98% figure sounds about right, doesn’t it? Eliminate 98% of C++ CVEs and that’s enough to compete with memory safe languages.
- nindalf 3y agoExcept the CVEs in Rust are far more likely to be low severity issues that C++ would never acknowledge to begin with.
- sirwhinesalot 3y ago
- CJefferson 3y agoComparing CVEs is unfair, in the past there have been CVEs in the Rust for things which in C++ were just marked “won’t fix” (this one: https://blog.rust-lang.org/2022/01/20/cve-2022-21658.html https://blog.rust-lang.org/2022/01/20/cve-2022-21658.html )
- kllrnohj 3y agoLinks to where C++ marked it "won't fix" please (hint: you won't find them, both libc++ and libcxx treated them with severity & promptness and resolved the issue quickly)
- dralley 3y agoBut still, there was no CVE filed, so comparing Rust to C++ on that front is apples-to-oranges. Rust has a lower bar for what can be considered a serious flaw.
- kllrnohj 3y agoThe libcxx & libc++ bugs both just pointed at the Rust CVE as a "this impacts us" - it doesn't seem like anyone bothered to file a CVE because they were too busy just fixing the issue. I don't see any evidence of this being some sort of standard for CVEs, especially since C++ doesn't have a CVE committee at all.
- burntsushi 3y agoSutter correctly points out that when using pointers in safe Rust, one is generally limited to tree structures. But, that one can express cyclic structures in safe code using other means (such as reference counting or integer indices): > One reason is that Rust’s safe language pointers are limited to expressing tree-shaped data structures that have no cycles; that unique ownership is essential to having great language-enforced aliasing guarantees, but it also requires programmers to use ‘something else’ for anything more complex than a tree (e.g., using Rc, or using integer indexes as ersatz pointers); it’s not just about linked lists but those are a simple well-known illustrative example. But then later on, seems to ignore the safe alternatives and commits a non-sequitur: > That’s because a language’s choice of safety guarantees is a tradeoff: For example, in Rust, safe code uses tree-based dynamic data structures only. This feature lets Rust deliver stronger thread safety guarantees than other safe languages, because it can more easily reason about and control aliasing. However, this same feature also requires Rust programs to use unsafe code more often to represent common data structures that do not require unsafe code to represent in other MSLs such as C# or Java, and so 30% to 50% of Rust crates use unsafe code, compared for example to 25% of Java libraries. In other words, Sutter acknowledges the safe alternatives at one point, but then ignores them later. When ignoring them, it allows Sutter to draw a conclusion as to why some percentage of Rust code uses `unsafe`. And even if ignoring those alternatives was appropriate here, I still see no reason to believe that 30%-50% of Rust crates use `unsafe` precisely because of the limitations around cyclic structures. There are many more reasons to use `unsafe`. [1]: https://thenewstack.io/unsafe-rust-in-the-wild/ https://thenewstack.io/unsafe-rust-in-the-wild/
- galangalalgol 3y agoI would have guessed most uses of unsafe dealt with c abi bindings. People do like to create interesting data structures in rust, but I don't see any of that in my cargo tree, and I suspect most people don't.
- soulbadguy 3y ago> But then later on, seems to ignore the safe alternatives and commits a non-sequitur I think it's possible to read the argument in the way that make sense. I don't think that Hurb is making the point here that Rust code uses more unsafe code pacifically "because" the the tree-base dynamic data structures restrictions. It seems that he took this simply as an illustration of a larger point. The point he is making is that programming language safety is always a trade-off. Rust and Java are making different trade-offs which results in a different level/kind of safety. We should also note, even if there are "safe" alternatives in rust, it doesn't mean those alternative are viable in term of code complexity, performance, cache behavior etc... etc... So the existence of safe alternative doesn't negate the need to use unsafe if one doesn't like the trade-off those safe alternatives imply. I don't think it's a particularly big problem that more part of rust are unsafe vs Java, and probably reflect rust focused on native performance more than anything else. But for the purpose the Hurb conversation here, this fact is important to note.
- 29athrowaway 3y agoRust started at Mozilla. Their products were written in C++, and despite all the effort put into good practices, they kept running into the same issues over and over. They designed a new language that would prevent those issues, and that became Rust. Personally, I think C++ has too much cognitive load. Over multiple decades, many features were added and very few were removed. The result of that process is having code that reads like mixing Latin with Ancient Egyptian hieroglyphs and then followed by TikTok jargon.
- humanrebar 3y agoMozilla also has struggles staying competitive with its core products. The main criticism of Rust as a solution to safety concerns is about that kind of outcome. Obviously Mozilla's challenges are multifaceted and don't boil down to user-invisible code rewrites. But, at best, switching to Rust was an orthogonal engineering concern that has opportunity costs.
- dralley 3y agoFirefox is competitive, their struggle is primarily that their competition is Microsoft, Apple, and Google, who have both practically endless wells of money, control over the computing platforms, and vastly more mindshare. There's no technical solution to that problem.
- humanrebar 3y agoYeah, that's a valid take. But if that's true, then Rust isn't giving them an edge (yet?). So it isn't the most important engineering task. If you're saying there's no technical path to success for Mozilla... well, that might be true, but I could see that being demotivating for Mozilla engineers.
- bsder 3y ago> Personally, I think C++ has too much cognitive load. I also think the same thing about Rust. RAII adds a humongous cognitive load to a language and I'm not really sure what you do about that. Zig is a step in the right direction with a bunch of the sharp corners in C filed down--slices and default non-null pointers is a big improvement. However, there are some things (like reference counted data structures) that are really annoying to implement in C/Zig that are really easy to implement in C++/Rust.
- DrBazza 3y ago"How do I get to Dublin?" "Well I wouldn't start here" I've been a c++ dev for 30 years. I'll be retiring in a decade (or perhaps keep going), and I doubt I'll ever see a 'safe' C++ in my working life. If the committee were even truly serious they'd adopt epoch releases and feature flags in the language spec (see Circle, doing it for real), starting in c++26, the next release. And adopting tooling as part of the standard like every other language. As usual, C++ is the outlier here. Then meaningful progress might start to be made in a measurable and testable way. Instead I'll read another dozen articles like this for next 5-10 years, and any talk of tooling or epochs will be kicked down the road for another few years as usual. But it's been a good lesson for all the other languages for better and worse.
- tcbawo 3y agoIMHO, Herb Sutter was spot on in his talk (https://youtu.be/fJvPBHErF2U https://youtu.be/fJvPBHErF2U) that it is impossible to walk back features of a language once they are in the wild. His cppfront is an interesting and refreshing approach. I think his “create a TypeScript for C++”, ie. generate safe, easy to understand, conforming C++ is the optimal path for where we are. Dealing with legacy codebases to evolve the language into something else is monumentally more difficult. And I tend to argue that maintaining legacy C++ systems with decades of features and bug fixes is okay for the right applications today.
- DrBazza 3y agoThat's Hyrum's law, basically. With feature flags and epochs, it is possible to evolve C++ in the right direction with the minimum of friction and make it opt-in in a consistent fashion. Circle already proves this a feasible approach, and that's a one-man project. There's also clang tooling that modernizes old C++, and huge amounts of work on LSPs and the like for refactoring, so it is possible to provide tooling that mechanically fixes-up a large portion of old code.
- Voultapher 3y agoAs much as I appreciate the intentions of those working on the successor languages, they have invariably already sunk the ship before even setting sail in my opinion. They are already too fragmented, Carbon, Cppfront, Circle and probably more. By fragmenting they destroyed the only viable future I saw for them. If you want the goals of those languages, there is Rust today that gives you that and more. I'm not alone with that opinion, I know several people in the C++ standard committee that think this way. Even fluent interop is a race they are loosing.
- htrp 3y agoAlso Unsafe for those under the age of 18 /s
- CyberEldrich 3y ago“We must make our software infrastructure more secure against the rise in cyberattacks (such as on power grids, hospitals, and banks)” How about not connecting your critical infrastructure directly to the Internet.
- AlotOfReading 3y agoWe have to work with the world that is, not the world that ought to be. Critical infrastructure is going to continue being accessible, so the people in charge of implementing those systems should have the appropriate tools to deal with the challenges it entails.
- ergonaught 3y agoThe cognitive burden of developing in C++ anymore is excessive, but that appears impossible to recognize without completely stepping away from the language for a few years. I loved the language; I even used it for web development for a couple of years and it was enjoyable to do so; but I did step away, and at this point I'd rather use Rust (a language I neither love nor find enjoyable). Not sure the C++ committee have the capacity to "fix" this (whatever that may mean), nor whether the industry would let them, even if they were able to recognize the cognitive burden as a problem.
- pjmlp 3y agoThere is a certain masochism and macho attitude in C++, see the C++ frameworks of the 1990's like OWL, VCL and CSet++, where C++ was as expressive as you could expect from a .NET or Java framework a decade later, something that only lives on C++ Builder and Qt/QtCreator. Both not really welcomed in most C++ circles, where naturally one codes close to C, with a thin layer abstraction wrapping OpenGL/Vulkan/DirectX in imGui for the ultimate performance, meanwhile the same authors use an Electron based application to write their code. This is what made eventually move away into managed compiled languages, C++ isn't really the same as used to be, my next favourite programming language similar in spirit to Object Pascal, as in the last century of desktop GUI frameworks.
- fulafel 3y agoWe're lucky that the LLM stuff came about after C++ was already in decline. Or could there be a resurgence of C++ if we can teach LLMs to tackle what humans can't?
- jvillasante 3y agoWhile other communities are already taking direct steps towards safety, the C++ community is still trying to define what safety means. I think it's funny and sad at the same time! I didn't read the article (just browse it) but here's the TLDR from the article itself: ``` tl;dr: I don’t want C++ to limit what I can express efficiently. I just want C++ to let me enforce our already-well-known safety rules and best practices by default, and make me opt out explicitly if that’s what I want. Then I can still use fully modern C++… just nicer. ``` As is normal in C++, the defaults are wrong. Developers should "opt in" for unsafe instead of "opt out" of it!
- soulbadguy 3y ago> Developers should "opt in" for unsafe instead of "opt out" of it! Why ? C++ guiding principle is zero cost abstractions.
- estebank 3y agoIt's "zero cost abstractions over what you would write by hand". If you argue that anyone doing array access should be doing bounds checks when in doubt, a C++ compiler performing bounds checks would still be considered zero(additional)-cost.
- pptr 3y agoWell, when you are not in doubt you don't want unnecessary bounds checks.
- estebank 3y agoIf you can communicate to a human that a bounds check isn't necessary, you can communicate it to a compiler.
- pptr 3y agoI'm all for better tools to help the compiler figure things out. Here is an example where I can't communicate the invariants to the compiler: ``` std::vector<int> v; ... v.push_back(2); std::sort(v.begin(), v.end()); // no need to check i < size because we know we will find value 2 somewhere in the v. for (int i = 0; i < v.size(); ++i) { if (v[i] == 2) return i; } ``` Note that in C++ you can manually mark code after the loop as unreachable, which would indeed skip the size check. But that's as bad as not checking bounds in the first place.
- saagarjha 3y agoAnother day, another essay from a C++ guy who is salty that the government called it insecure and thus seeks to compare the best possible version of C++ with his misunderstanding of what everyone else is doing, and doing a poor job at that too. The stuff Herb mentions as solving "98% of the problems" do not do that. First of all, they don't do that now, because they aren't on by default. At least he accepts this, but people have been claiming that C++ is great now because all these things are easy to do, and the fact is that nobody actually does it. Every other language is shipping this as table stakes and C++ hasn't even gotten its pants on yet. Second, in the surfaces that do actually care about this (think web browsers) they are putting a huge amount of time and money into solving this regardless of what the language does by default. We're talking automatic initialization, bounds checks enabled by default, all sorts of smart pointers and "production" sanitizers. They are still being exploited. Yes, your average script kiddie isn't taking down Chrome these days. But nation states still do it. They don't care that you go to 98%! They find a bug, they exploit it. The rest of the post is just the usual talking points against every other language that exists. A lot of it is wrong. I'm not going to dwell on the whole "Rust takes CVEs that C++ doesn't" argument because I think this misses the point, personally (Rust has a different safety model, so problems under that safety model are just as valid problems with Rust. You can't go "oh we are safer by default" and "oh actually this makes things a lot harder for us so don't judge us when things are broken). However, a lot is just wrong. Languages that do not corrupt their VMs on races are better in many ways than C++, because in C++ anything of that sort is basically a direct path to code execution. In other languages you have to work for it. In Rust people use unsafe–but that doesn't mean it's automatically as unsafe as C++. It just means that people write a little bit of code using it and then build on top of it. In garbage collected languages the runtime gets super upset if you hold on to references when it thinks you shouldn't. However, doing this is a performance and in some cases an issue of leaking resource. It is not comparable to, say, a UAF in C++. Basically, you can't just go "oh every other language has [problems I looked up on Google] this means they are also bad". Because in C++, the problems almost invariably lead to a foreign government taking control of your phone. This is not true for other systems.
- deleted 3y ago[deleted]
- posix_monad 3y agoReplacing circular structures with IDs is memory-safe, but it can still blow up if there is no item with that ID. It may be safer, but it's not guaranteed correct or anything like that. In these cases I'm not sure what is gained by Rust over C++.
- Filligree 3y agoThe... memory safety? It will reliably blow up; that's quite an improvement already, when the alternative may be remote code execution. There's also of course everything else, like the ergonomics, freedom from data races and so on, but I'll skip that.
- hgs3 3y agoWhether software blows up or not if an ID is "bad" depends on how it's written. Writing a token to a database without cleaning it up could lead to a security hole that has nothing to do with memory exploitation. I worry the fixation on memory is creating tunnel vision.
- fch42 3y agoHerb Sutter makes that point though somewhat hidden amongst all the apologetics... let's not forget there are security vulnerabilities that don't originate in memory access violations. "Easy" config mistakes, bad secrets protection, and human-factor-exposure are out there and don't depend on memory safety. Being humble about that would be only fair.
- deathanatos 3y agoI'm actually surprised their example wasn't the accidental use of a valid ID, not an invalid one. An invalid one is easily catchable, but an invalid one is akin to a bad pointer. The resulting behavior will slip by the Rust compiler, as we're basically using integers as pointers, and you can get all sorts of shadow-clone versions of malignant pointer behavior like use-after-free in such a scheme. That said … there are ways in Rust to do circular data structures that don't have the problems that using indexing into an array has, and are memory safe, and are within the safe subset of Rust. (E.g., Rc/Arc.)
- richrichie 3y agoWhy not just use Go?
- soulbadguy 3y agotoo slow...
- pjmlp 3y agoFast enough for large majority of projects on CNCF project landscape, where C and C++ are a minority.
- pptr 3y agoGo is a great language, but there also needs to be a language that you can program with zero overhead.
- vlovich123 3y ago> Many of the most damaging recent security breaches happened to code written in MSLs (e.g., Log4j) or had nothing to do with programming languages (e.g., Kubernetes Secrets stored on public GitHub repos). I’m surprised Herb is so defensive here. He normally strikes me as level-headed but he’s arguing in bad faith here. There’s no way a language can prevent arbitrary code execution if the programmer intentionally wants to allow it as a feature & then doesn’t think through the threat model correctly or not managing infrastructure secrets (the latter btw is mitigated by Microsoft’s own efforts with GitHub secret scanning although there should be more of an industry effort to make sure that all tokens are identifiable). But C/C++ is a place where 60-80% of the vulnerabilities are regularly basic things the language can mitigate out of the box. No one is talking about perfection. But it’s disappointing to see Herb stuck and arguing “there’s other problems and even if memory safety is an issue Rust has problems too”. The point is that using Rust is a step function improvement and provides programmers with the right tools so they can focus on the other security issues. A Rust codebase will take more $ to exploit than a C/C++ one because it will be harder to find a memory vulnerability which is easier to chain into a full exploit vs attacking higher level stuff which is more application specific. EDIT: And language CVEs are a poor way to measure the impact of switching to Rust because it’s the downstream ecosystem CVEs that matter. I’m really disappointed this is the attitude from the C++ community. I have a lot of respect for the people working on it, but Herb’s & Bjarne’s response feels like an unnecessary defensive missive to justify that C++ is still relevant instead of actually fixing the C++ ecosystem problems (namely their standards approach is making them move too slowly to ever shore up their weaknesses).
- nindalf 3y agoTheir defensiveness makes sense in the current context where in the last few weeks organisations like the White House [1] and Google [2] are explicitly calling out the importance and imminent need of moving away from memory unsafe languages like C and C++. If everyone focussed on this one issue, it is possible that we might actually start moving away from C and C++ in the next 5-10 years. Sutter pointing out that memory safety isn't the only vector for system vulnerabilities would have the effect of spreading cybersecurity efforts and budgets across all of them. In that case memory safety isn't the foremost problem it's being portrayed as, and it isn't worth migrating away from C and C++. [1] - https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-... [2] - https://research.google/pubs/secure-by-design-googles-perspective-on-memory-safety/ https://research.google/pubs/secure-by-design-googles-perspe...
- kwant_kiddo 3y agoI think it is remarkable how important ABI is to C++. I think 'making it easier to enable them' i.e. enable the sane defaults went down the drain once they locked in on not breaking ABI. I am sure that Herb wrote this with good intentions, but no concrete measures was proposed but trying to standardize compiler tools, and to some extent downplay Rust. I agree there is a misconception around programming safety, but this reads the same as when big industry say the want to focus more on climate change.
- morning-coffee 3y agoI just can't help but have the feeling that the ship is sinking and this article busies itself with arguing over how much spackle is sufficient to plug one of the many holes. There is too much UB allowed in the C++ spec to be worth saving at this point. Focusing only on CVE reduction still punts on all the money and time wasted with buggy software because the language cannot do much to prevent data races, for example.
- loeg 3y agoC++ also brings the baggage of dogshit syntax and extremely verbose and confusing types and error messages that new languages do not suffer from. I get why this guy who has built his career in C++ is defensive of C++, and certainly existing codebases cannot be migrated overnight or even ever, but I would not start a new project in C++ if I could help it.
- pizlonator 3y agoThere isn’t too much UB for it to be fixed. Fil-C fixes it (albeit just for C, for now). CHERI fixes it (and it works great for C++). There are other systems that fix it, too.
- pjmlp 3y agoUnfortunely Intel and AMD keep shoting themselves in regards to memory tagging implementations.
- jupp0r 3y agoI have tremendous respect for Herb Sutter and I can understand where he is coming from, but things like "All dereferences are null-checked. The compiler injects an automatic check on every expression of the form *p or p-> where p can be compared to nullptr to null-check all dereferences at the call site (similar to bounds checks above). When a violation happens, the action taken can be customized using a global null violation handler; some programs will want to terminate (the default), others will want to log-and-continue, throw an exception, integrate with a project-specific critical fault infrastructure." make me just feel sad about the future of C++. The problem is not only CVEs, the problem is that the language makes doing the right thing hard and doing the wrong thing easy. All larger C++ projects I've worked on already use an enormously complicated and fragile combination of compiler-warnings-as-errors, static analyzers and linters to fix these problems and standardizing these is a worthwhile effort to reduce differences between different compilers and tools and to get to a bare minimum standard that everybody can agree on. The problem is that most projects won't adopt these until the 2030s or 2040s and then they will only create a bare minimum bar of safety and convenience when new projects could just use Rust and get a very well thought out safety model and other benefits (no inheritance, const-by-default, etc) at little extra cost. The type system and metaprogramming capablities of C++ are really nice (when compared to Rust), but at this point the language is only relevant for the existing (thriving) codebases that use it and for historic reasons, but no sane person would choose it for an new project anymore, which makes me sad. I don't see how C++ can reinvent itself and stay relevant without a radical break that takes the last 20 years of language development into account. Also, finally put some coroutine compatible event loop in the standard library FFS, it's 2024.
- ubj 3y agoIt's interesting to compare these opinions with those of the Google Security team that were released a little over a week ago [1]. Key quotes from the Google paper: > We see no realistic path for an evolution of C++ into a language with rigorous memory safety guarantees that include temporal safety. > In our experience, it is not sufficient to merely make safe abstractions available to developers on an optional basis (e.g. suggested by a style guide) as too many unsafe constructs, and hence too much risk of bugs, tend to remain. Rather, to achieve a high degree of assurance that a codebase is free of vulnerabilities, we have found it necessary to adopt a model where unsafe constructs are used only by exception, enforced by the compiler. It seems like Herb Sutter at least partially agrees with the second point in his TL;DR: > I just want C++ to let me enforce our already-well-known safety rules and best practices by default, and make me opt out explicitly if that’s what I want. [1]: https://security.googleblog.com/2024/03/secure-by-design-googles-perspective-on.html?m=1 https://security.googleblog.com/2024/03/secure-by-design-goo...
- soulbadguy 3y ago> Rather, to achieve a high degree of assurance that a codebase is free of vulnerabilities, we have found it necessary to adopt a model where unsafe constructs are used only by exception, enforced by the compiler. Yeah that sound like most security researcher i have talked/listen to. They see the problem as safety maximization problem. While in the real world, there are 50 different other constraints that a language design needs to navigate.
- PH95VuimJjqBqy 3y ago> We see no realistic path for an evolution of C++ into a language with rigorous memory safety guarantees that include temporal safety. The point Herb was making is that "rigorous memory safety" isn't the only bar, nor should it be. Saying there is no way to make C++ have rigorous memory safety is not the same as saying C++ can never be made safe.
- 8f2ab37a-ed6c 3y agoHaving recently had to pick up C++ again after over a decade in Ruby/Python/Clojure/Haskell/TypeScript land, it was enlightening to see how much the language is a window into a previous era of programming, full of boilerplate and footguns and dreams for programming patterns that ended up non panning out. It feels like the programming community can do so much better, having seen the other side of it, but there's an immense amount of legacy code that's holding us back. Especially if you're going into more serious game dev territory, it seems practically unavoidable.
- pizlonator 3y ago> If there were 90-98% fewer C++ type/bounds/initialization/lifetime vulnerabilities we wouldn’t be having this discussion. I disagree. We shouldn’t aim for 90-98%. We should aim for 100%. Reason: unlike logic errors, memory safety bugs are exploitable more often than not. Logic errors are usually just some useless glitch and only sometimes exploitable. > rust has 6 CVE’s Couldn’t quickly check if any of those six were memory safety or not. It’s sad that rust still has memory safety issues and if that’s true then my conclusion is that rust isn’t safe enough.
- steveklabnik 3y ago> It’s sad that rust still has memory safety issues and if that’s true then my conclusion is that rust isn’t safe enough. Let's assume all the CVEs are memory safety issues (some are not, some are, in reality.) Even then, they're things like "a bug in the standard library" that was then fixed. All software has occasional bugs. It is not possible to never have bugs.
- aapoalas 3y agoIn workplace safety, at least in my country, there is a commonly accepted level to aim for: No accidents. It makes sense in a way. If you don't aim for zero, what do you aim for? A few hands lost in a month? A few crushed fingers? In this viewpoint I'd argue that aiming for a 98% reduction is a bit absurd: "Yeah we had an issue but it was the only one this month so it's within our budget." Of course, goals are not the same as realised results. Getting a 98% reduction should be considered a huge, huge win. The next step should then be "what can we do to get rid of the rest?" Or at least the alternative seems odd: "We got this far, job done, nothing useful to do anymore." Of course, the means will change. If C++ guarantees full memory safety next month, then the next steps after that won't be more memory safety but something else.
- pizlonator 3y agoThat's a really good way of stating what I believe. :-) If C++ had memory safety next month then the next step would be to add stronger types. Once memory safety is a thing, you can start to add types that describe contracts and then you can ensure lots of interesting logical safety properties that aren't memory safety.
- jbiason 3y ago> not all code can be easily updated to conform to safety rules (e.g., it’s old and not understood, it belongs to a third party that won’t allow updates, it belongs to a shared project that won’t take upstream changes and can’t easily be forked). I have to say, this sentence annoys the heck out of me. Old code that can't be understood needs to be rewritten anyway. And since you're rewriting, you can apply the safety rules -- which would be better anyway. If the code belongs to a third party and they don't want to update, it means the third party is playing against you -- or, worse, that they control how you're going to move forward. It's in your best interest, in this case, to rewrite the third party dependency as soon as possible, and since you're rewriting, you can apply the safety rules -- which would be better anyway. If the code is shared and the upstream does not accept patches and -- worse -- doesn't support forks, then you have an issue with the upstream anyway and -- guess what -- you'd be better rewriting it anyway. All those issues are managerial issues, not software issues. Management decided that it is better to be stuck than moving forward. And they can happen with any languages, not just C++. Adding these things as "we can't be totally safe" are like "I can't jog every afternoon 'cause bears/alligators/wild life may jump an attack me". It's pure excuse to NOT do things.
- PH95VuimJjqBqy 3y ago> I have to say, this sentence annoys the heck out of me. > Old code that can't be understood needs to be rewritten anyway. I don't think it's that old code can't be understood, you can always understand what code is doing mechanically. it's a question of can you predict the consequences. For example, if I rename this database column, what in our systems that have been built over the last 30+ years will explode? That's data rather than code, but the underlying idea is the same. What happens is the very act of rewriting it puts you at risk of adverse effects.
- summerlight 3y agoAfter using the modern C++ more than 10 years, I don't believe the "safe subset" is sufficient to solve the security problems in C/C++. It does help, but not enough to keep the pace of modern software complexity. Some of localized anti-patterns could be prevented, but any non-trivial memory bugs across team boundary won't be.
- madmax96 3y agoThis post contains a number of statements that mislead the reader into believing that we are overreacting to memory safety bugs. For example: > An oft-quoted number is that “70%” of programming language-caused CVEs (reported security vulnerabilities) in C and C++ code are due to language safety problems... That 70% is of the subset of security CVEs that can be addressed by programming language safety I can’t figure out what the author means by “programming language-caused CVE”. No analysis defines a “programming language-caused CVE”. They just look at CVEs and look at CWEs. The author invented this term but did not define it. I can’t figure out what the author means by “of the subset of security CVEs that can be addressed by programming language safety”. First, aren’t all CVEs security CVEs? Why qualify the statement? Second, the very post the author cites ([1]) states: > If you have a very large (millions of lines of code) codebase, written in a memory-unsafe programming language (such as C or C++), you can expect at least 65% of your security vulnerabilities to be caused by memory unsafety. The figure is unqualified. But the author adds multiple qualifications. Why? [1] https://alexgaynor.net/2020/may/27/science-on-memory-unsafety-and-security/ https://alexgaynor.net/2020/may/27/science-on-memory-unsafet...
- bfrog 3y agoSafety as in undefined behavior isn’t in a subset of the language or safety as in memory safety? Because Rust tries to do more than memory safety and it’s quite amazing. Integer overflow isn’t an unheard of problem. The 787 had an integer overflow problem in C about a decade ago. The most recent drama with the entire FCU going dark seems eerily similar to what you might expect where a watchdog would reboot it.
- lionkor 3y agoWe C++ developers like that C++ is easy to fuck up, because we think we know better, and we think that means job security.