5 ms·
Question to C++ pros: are there not idioms that can be used and ruthlessly enforced to avoid such problems entirely? Is this the result of 'open use of pointer
by jariel 6y ago
Question to C++ pros: are there not idioms that can be used and ruthlessly enforced to avoid such problems entirely?
Is this the result of 'open use of pointers' that inevitably causes problems here and there?
Or is this problem due to the fact is just impossible to use even hard idioms to avoid such problems? (Or hard to enforce them?)
On some small-to-midsized projects I've seen narrow and rigorously enforced rules around pointers that seemed to work well. So what's up?
- necubi 6y agoIf you try to strictly enforce memory safety in C++, you end up with code that looks a lot like Rust. But the Rust compiler will fail to compile code that has memory-safety issues (outside of unsafe blocks), while your C++ compiler will happily ignore them.
- jandrewrogers 6y agoThe challenge is that the Rust compiler will fail to compile many codes that are strictly and provably memory safe but fall outside Rust’s narrow model of “memory safe”, and which are required for performance reasons. You’d have to wrap most of the code in unsafe blocks. In C++17 you can directly write type infrastructure that transparently enforces memory safety models that Rust doesn’t grok, which is a pretty nice feature. Many people underestimate what is possible using C++ these days. Complex for sure, but also very powerful.
- kelnos 6y ago> Many people underestimate what is possible using C++ these days. Complex for sure, but also very powerful. And that's the problem. There are very few true C++ experts, and most people will run into these issues as a matter of course. This just feels like a reduction to the usual: if you are perfect, you will write perfect code, and never have memory-safety bugs. Thanks, but I'm not perfect, and I'd rather write in a language with a compiler that rejects programs with memory-safety bugs. And yes, that does mean sometimes it'll reject some programs that are perfectly ok, but the Rust borrow checker is getting better all the time, and sometimes you just have to accept being hamstrung a little for the greater good.
- manaskarekar 6y agoThere are the Core Guidelines : https://github.com/isocpp/CppCoreGuidelines https://github.com/isocpp/CppCoreGuidelines.
- aloknnikhil 6y agoIn addition to the isocpp guidelines, using the Address/Undefined Behavior Sanitizer goes a long way.
- saagarjha 6y agoI believe Chrome makes heavy use of both. The issue is that they are not precise and they are inherently coverage-guided, so you may still never hit certain issues.
- Falell 6y agoThere are idioms that you can use to help. Bounds checking solves the classic indexing past arrays problem and you can use tools to prove that you never use e.g. the basic operator[]s on types for which it is not safe. Some of these idioms are not zero-cost though. My understanding is that to prevent use-after-free you basically can't use bare pointers or references, at all, ever. You need shared ownership everywhere (std::shared_ptr, not 0 cost), a garbage collector (In c++ that's probably another smart pointer type, not 0 cost), or additional metadata like the lifetimes fed into Rust's borrow checker. Based on my reading here on HN, I think Chrome has a reputation of using modern C++ features extensively to try to improve its memory safety, but it's really hard to do in C++. Edit: I realized this answer sounds like "yes idiom will fix it". To directly answer the question of "can you use idioms to fix this", no you can't. Evidence shows we screw it up. It's broken and you can't bolt on fixes to make it work.
- cryptofistMonk 6y agoContainers and smart pointers will pretty much do the trick. There's really no need for manual memory management anymore, can't remember the last time I used new/delete. Only problem is most large C++ apps, Chromium included, are older than a lot of the language features that have made C++ much safer these days.
- zetafunction 6y agoEven though Chromium was started before C++11 was standardized, it still used a smart pointer type with move semantics that was very similar to std::unique_ptr for lifetime management. However, while lifetime management with smart pointers is certainly important, it doesn't help with non-owning pointers between objects.
- MaulingMonkey 6y ago> Question to C++ pros: are there not idioms that can be used and ruthlessly enforced to avoid such problems entirely? "In theory, yes - in practice, no." You can use static analysis, vendor-specific annotations, runtime tools like clang's various sanitizers or valgrind, thorough code audits, use smart pointers instead of raw, have clear ownership semantics, follow MIRSA C guidelines, NASA guidelines, etc etc etc... but eventually your project will grow to the point where you'll botch an edge case, and the number of botched edge cases all your coworkers manage to add up will turn into a statistic. Even if me and all my coworkers were all godlings incapable of making mistakes, we'd still end up debugging plenty of memory safety issues - in second/third party code, sometimes without source code, and writing bug reports / workarounds as a result.
- jillesvangurp 6y agoAlso, you can assume Google to be using all of the tools at their disposal. The stakes are high for them and they've been dealing with security issues for a long time. It helps, but it's obviously not enough. This seems to be true for most widely used C/C++ code bases; including those with decades of scrutiny. At best some projects have a good track record when it comes to dealing with these issues in a diligent way. Chromium seems to be one of those projects.
- saagarjha 6y agoI have long imagined a much weaker form your desire: a C++ runtime that detects all undefined behavior in the code that executes. Note that it is nowhere near the goal we want, which is that the program has no memory safety issues at all. Even though there are many static and dynamic analysis tools that exist today, with runtime penalties ranging from almost zero to extremely high overhead, I have yet to see a system that can do this. So I would guess that no, this is not possible. There might be a magic set of idioms, but my guess is that finding that set is going to be so impractical that we will never do it, or someone is going to write a proof that that set is empty and we will just go on living our lives slightly more depressed at the state of computing.
- tialaramex 6y agoHumans don't do "ruthless" enforcement, machines are good at it which is what Rust is about. Humans will say stuff like "well, I'm pretty sure this is safe and I need every CPU cycle I can get". This is a security consideration so the bad guys only have to be lucky once, it's like the IRA told Thatcher (British Prime Minister, after a failed assassination attempt): "Today we were unlucky, but remember we only have to be lucky once. You will have to be lucky always."
- zetafunction 6y agoThe object graph in Chromium is extremely complex. Even if an object's lifetime is managed with a smart pointer, there are often raw pointer back references from other objects. And if some of these objects also have lifetimes coupled to IPC or work happening on other threads… well, you can imagine the result :) Of course, one could make all the back references weak, but that turns out to also significantly hinder understanding of the code. It ends up being really easy to lose all assertions about when any given object that's weakly reference is actually supposed to be live, and you end up with code that's littered with checks everywhere "just in case".