7 ms·
> And C++ just... doesn't have that many real problems. It does not have many, but it has one and it's big. It's not memory safe. Check out this talk by Herb
by credit_guy 4y ago
> And C++ just... doesn't have that many real problems.
It does not have many, but it has one and it's big. It's not memory safe.
Check out this talk by Herb Sutter, around minute 43:
This is the first time a government [see note] has actually issued guidance to industry broadly that was the barest paraphrase away from "where possible don't use C and C++"
[ Note: in this context, the "government" is the US Department of Commerce and NIST, which, according to Herb, have issued a detailed guidance in response to the Executive Order on Cybersecurity [2]. While I couldn't find that guidance, I found one by the NSA [3], which saw quite a few comments here on HN in December last year [4] ].
[1] https://www.youtube.com/watch?v=ELeZAKCN4tY https://www.youtube.com/watch?v=ELeZAKCN4tY
[2] https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/ https://www.whitehouse.gov/briefing-room/presidential-action...
[3] https://media.defense.gov/2022/Nov/10/2003112742/-1/-1/0/CSI_SOFTWARE_MEMORY_SAFETY.PDF https://media.defense.gov/2022/Nov/10/2003112742/-1/-1/0/CSI...
[4] https://news.ycombinator.com/item?id=33560227 https://news.ycombinator.com/item?id=33560227
- s9w 4y ago[dead]
- zik 4y ago> It's not memory safe Modern C++ has made big inroads into removing memory safety issues though. Memory safety bugs are relatively uncommon in modern C++ compared to pre C++11 times. You could argue that C++ is still "unsafe by default" and you'd be right. But most C++ programmers use smart pointers and unique pointers rather than raw pointers now, vectors instead of raw arrays, etc.. And it does make a big difference.
- TazeTSchnitzel 4y agoAren't vectors just as vulnerable to out-of-bounds access as any C-like array? Most C++ additions have plenty of undefined behaviour.
- patrick451 4y agoNot if you stick with the ::at() method, which does bounds checking https://en.cppreference.com/w/cpp/container/vector/at https://en.cppreference.com/w/cpp/container/vector/at
- agwa 4y agoUnfortunately, std::span doesn't have at(). Note that std::vector's at() predates C++11, whereas std::span was added in C++20. It's a myth that C++ is getting more memory-safe; in many aspects it's actually regressing.
- kazinator 4y agoRegardless of all that, you can make your own vector class which works exactly how you want and is completely safe. In a greenfield project where you control every line of C++ code, you can easily achieve very good safety using nothing but ancient C++ features. Not just memory safety. I mean, you can make your own numeric types that do overflow checks and throw exceptions or whatever. It probably won't be very fast, but it will be solid. People have used C++ (ancient C++) to make numeric types with units, where you can't add "kilograms per second" to "meters". I remember that from some talk thing I went to in 1999.
- LaLaLand122 4y agostd::span doesn't have at() because std::logic_error was a mistake. Using std::vector's at() is a mistake (you could use it as a helper method and make it as if it throwed std::runtime_error, but it doesn't, that wasn't its intended usage). All three major C++ standard library implementations have an option to enable assertion checks in both std::vector and std::span operator[]. Enable them unless you are in such a resource limited environment that you can't afford the checks (unlikely). The only reason the standard doesn't require the checks is to allow C++ to be usable in those resource limited environments. You could argue the checks should be enabled by default, but that's not something for the standard to decide, complain to your standard library vendor.
- hot_gril 4y agoIt's not that people can't deal with pointers. The most common issue in C++ is how many ways to shoot yourself in the foot with common utils. Like, we use a lot of abseil utils at work that return string_views instead of new strings, and if you're directly passing that somewhere else, you easily corrupt your memory. std::string foo = "foo"; const std::string foo2 = absl::StripAsciiWhitespace(absl::AsciiStrToUpper(foo)); // in Python: foo2 = foo.upper().strip() std::cout << foo2; // garbage Yeah, all technically the user's fault, but it gets pretty tiring worrying about this stuff when you're writing a high-level application and the few CPU cycles you save don't really matter. No matter how good you are, you will make mistakes, and the chance of one bug corrupting memory in your whole process increases exponentially with the LoC written. Also I have to point out the irony in a language being type-safe but not memory-safe. Also, I didn't expect Java-looking class syntax to leave member variables uninitialized (garbage) if you don't set a default. That should at least be a compiler warning, I mean how often do you actually want that?
- okamiueru 4y ago> Also I have to point out the irony in a language being type-safe but not memory-safe. Misnomer aside, there is no contradiction. Type safety is much easier to reason about at compile time than memory management. So, it shouldn't come as a surprise. You need a rust like "borrow checker"-by-default functionality.
- hot_gril 4y agoIt's not surprising that they use static types in C++, but it's not about safety. It's about knowing the size of everything at compile time. Dynamic typing requires moving more towards the "interpreted" side of languages and incurring the performance cost of that. The contradiction is when the veteran SWEs I work with say we use C++ instead of Python for the added safety of compile-time type checks, treating dynamic typing like a bigger risk than memory trampling (never mind that Python has type-checking too if you really want it).
- bluGill 4y ago
- moefh 4y ago> Modern C++ has made big inroads into removing memory safety issues though Modern C++ adds new features that allows you to write code that doesn't have as many memory safety problems, but all the unsafety (is that a word?) that existed in the past still exists. Removing features that allows memory unsafety will probably never happen, because one of the main reasons people use C++ is all the legacy code will still be used for decades. It's great that you can write C++ using only the newest features, and that does increase safety. But that doesn't offer the same guarantees of languages designed to simply not have these kinds of problems, or that by design flag the points in the code where safety can't be guaranteed by the compiler.
- kazinator 4y agoYou can write completely memory-safe code using nothing but C++98 features, like templated smart pointers and whatnot, which wrap around the unsafe parts of your code. You can keep that unsafe part small and get it right "by inspection"; then if it's used through the higher level primitives, it cannot be misused.
- moefh 4y agoThe problem is that there's no way to automatically check any of that. If the code is small and doesn't change or doesn't have to last for too long, that's OK. But when it's changed over the years, it's pretty much impossible to guarantee that the unsafe parts are kept small and contained, especially as programmers leave and new ones come in.
- midoridensha 4y agoC++ has so many features that it looks like a different language, depending on who's writing it. It can still compile decades-old code written to the oldest standard, or brand-new code with the latest memory safety features. So is there a compiler flag or external linting tool that can generate warning messages when you're using an older memory-unsafe technique where a safer and more modern technique could replace it?
- Kranar 4y agoThis is simply false, modern C++ just replaces old issues with new ones. There are numerous new unsafe footguns that "modern" C++ introduced with lambda captures, coroutine lifetimes, and libraries like std::range where lifetimes and ownership are incredibly difficult to reason about. Not to mention that the web is full of blog posts about how to properly use std::string_view, since a lot of crashes trace back to improper use of it, particularly its constructor that kind of acts like it takes ownership but doesn't.
- lmm 4y ago> Modern C++ has made big inroads into removing memory safety issues though. Memory safety bugs are relatively uncommon in modern C++ compared to pre C++11 times. I remember when people said the same thing about C++03. Plus ca change.
- kazinator 4y agoIt was true, which makes it silly to be saying it about C++11, C++14, C++17, ... In C++98 you could develop a program with some unsafe core of whatever resource management you wanted, and then wrap it with the right classes so that it can't be misused. After circa 1995, anyone struggling memory safety issues in greenfield C++ code that was completely under their control (no legacy) had to be a supreme goofball not to be leveraging the language to make that sort of thing go away.
- lmm 4y agoAnd yet we keep seeing memory safety issues in C++ code even when that code was written greenfield long after 1995. (E.g. IIRC cloudflare's cloudbleed was in a codebase that had been started in about 2012).
- kazinator 4y agoLooking at this, that is not clear. The report below (courtesy of Wayback Machine) mentions some external HTML libraries, as well as the development of modules that plug into NGINX, and work on raw memory buffers (I'm guessing, dictated by NGINX). Hard to speculate without seeing the code. Not that it's an excuse; greenfield C++ code could find ways to interface in a bullet-proof way with something or anything that communicates using low-level buffers. The "Ragel" tool they used evidently generates C that uses raw pointers: > The Ragel code is converted into generated C code which is then compiled. The C code uses, in the classic C manner, pointers to the HTML document being parsed, and Ragel itself gives the user a lot of control of the movement of those pointers. The underlying bug occurs because of a pointer error. The bug in these Ragel-generated parsers was somehow hidden or compensated for by some buffering strategy, which they tweaked when introducing some new kinds of parsers "cf-html". Those didn't have the bug, but the different buffering turned on for them exposed the bugs in the Ragel based parsing. https://web.archive.org/web/20170223233000/https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/ https://web.archive.org/web/20170223233000/https://blog.clou... I'm looking at the Ragel State Machine Compiler user guide. Chapter 5 (Interface to Host Program) makes it quite clear what sort of thing the Cloudfare people chose to grapple with. Ragel will write code for you planted into middle of any C function anywhere; you must provide numerous predefined variables, under prescribed names, some of which are pointers to data, and so it goes. For some languages, there are safer interfaces: for Java and Ruby there is a buffer and instead of a pointer there is an index into it. Ragel could have been upgraded to have actual C++ support of some kind.
- pjmlp 4y agoMost programmers sadly keep using C idioms even while writting "modern" C++, just look at recent samples provided by companies with seat at the ISO table, some of which have even provided famous security reports.
- patrick451 4y ago> > And C++ just... doesn't have that many real problems. > It does not have many, but it has one and it's big. It's not memory safe. It's not as big as a deal as c++ opponents make it out to be. The ratio of memory bugs to other bugs at work is basically zero. The problems that are holding our product back have nothing to do with memory safety. Of the long list of problems we need to solve, that just isn't one of them. If the only thing a new language offered over c++ was that I don't have to think about that 0.01% of bugs anymore, but in exchange I get either a garbage collector or a borrow checker to fight with, I would not switch.
- FpUser 4y ago>"It does not have many, but it has one and it's big. It's not memory safe." Enough of this already. Not going to discuss ancient code. I currently using modern C++ and it has enough features to keep one's code reasonable safe if that was the goal. And frankly I do not remember any reported bugs in my production caused by "memory unsafety". Just plain old logic errors every once in a while.
- akira2501 4y ago> It's not memory safe. The computer isn't "memory safe." If you want a language that can express every function of the hardware it runs on, you expose this fact as well. Careful management of "unsafe" blocks might be an answer, but I suspect we're going to have to dig way deeper until we find a truly "safe" solution. At that point, would it actually matter which language you use?
- nindalf 4y ago“There’s going to be some bugs no matter what we do. So why try substantially reducing 70% of the bugs we see?” https://www.chromium.org/Home/chromium-security/memory-safety/ https://www.chromium.org/Home/chromium-security/memory-safet... https://msrc.microsoft.com/blog/2019/07/a-proactive-approach-to-more-secure-code/ https://msrc.microsoft.com/blog/2019/07/a-proactive-approach...
- akira2501 4y agoI'm saying fix them. I'm also saying, I don't think the language is the appropriate level to do this at. You can see the clear conflict in the mentality of these new languages. "Fast and, somehow, safe!" It's missing the forest for the trees, much like your retort.
- nindalf 4y ago> Fix them. People are. Like on Android. > In Android 13, about 21% of all new native code (C/C++/Rust) is in Rust. There are approximately 1.5 million total lines of Rust code in AOSP across new functionality and components such as Keystore2, the new Ultra-wideband (UWB) stack, DNS-over-HTTP3, Android’s Virtualization framework (AVF), and various other components and their open source dependencies. These are low-level components that require a systems language which otherwise would have been implemented in C++. > To date, there have been zero memory safety vulnerabilities discovered in Android’s Rust code. > We don’t expect that number to stay zero forever, but given the volume of new Rust code across two Android releases, and the security-sensitive components where it’s being used, it’s a significant result. It demonstrates that Rust is fulfilling its intended purpose of preventing Android’s most common source of vulnerabilities. Historical vulnerability density is greater than 1/kLOC (1 vulnerability per thousand lines of code) in many of Android’s C/C++ components (e.g. media, Bluetooth, NFC, etc). Based on this historical vulnerability density, it’s likely that using Rust has already prevented hundreds of vulnerabilities from reaching production. Source: Memory Safe Languages in Android 13 https://security.googleblog.com/2022/12/memory-safe-languages-in-android-13.html?m=1 https://security.googleblog.com/2022/12/memory-safe-language... But sure, keep telling yourself that it’s possible to write C++ code of this quality by being more careful or using some magical sanitizer or by hiring better developers or whatever.