8 ms·
Have to say that nothing can make your program automatically safe (defined by common sense, not "memory leaks are also memory safe"[0]) without any effort, and
by htfy96 8y ago
Have to say that nothing can make your program automatically safe (defined by common sense, not "memory leaks are also memory safe"[0]) without any effort, and the trend to claim some languages are inherently "safe" while others are not is definitely a hype. Modern C++ plus static analyzing (Chromium rolled out their own Clang plugins to do that) provides better flexibility.
[0]: http://huonw.github.io/blog/2016/04/memory-leaks-are-memory-safe/ http://huonw.github.io/blog/2016/04/memory-leaks-are-memory-...
- pcwalton 8y agoVirtually nobody in security agrees with you. Memory-safe languages do effectively mitigate some of the most critical security issues. C++ static analysis is helpful, but it is not memory safe. Modern C++ doesn't really help. In fact, in my opinion, modern C++ tends to be less memory safe than "classic" C++, because it adds all sorts of new fun ways to get use-after-free.
- daeken 8y agoPeople drastically underestimate the prevalence and impact of UAF attacks. They're extremely common in complex applications and often lead to everything from information leaks to code execution. That's why almost every browser exploit (of the last ~10 years at least) uses at least one UAF in their chain.
- saagarjha 8y ago> That's why almost every browser exploit (of the last ~10 years at least) uses at least one UAF in their chain. That's usually because the "low-hanging fruit" is mostly gone due to protections like stack canaries, CFI checks, address randomization, and sandboxing, which makes things like buffer overflows or jumping to shellcode more difficult.
- jupp0r 8y ago> Modern C++ doesn't really help. In fact, in my opinion, modern C++ tends to be less memory safe than "classic" C++, because it adds all sorts of new fun ways to get use-after-free. I think modern C++ is much safer than legacy C++, not by disallowing the USE after free, but by giving you the tools to make sure that the FREE happens at an appropriate time. A lot of this is not necessarily a feature of the language itself, but of idioms the community seems to agree to ie CppCoreGuidelines. I'm thinking of - never use the delete operator manually, prefer std::unique_ptr - prefer single ownership over shared ownership - prefer immutable over mutable state - ... I agree with you that compared to Rust, this places a lot of burden on code reviewers and is in no way perfect, but I wouldn't say it's going in the wrong direction, making the language less safe.
- pjmlp 8y agoThat is the thing though, I never did code reviews in C++ projects and have been often in the past (in my C and C++ days) the dude playing the D.Quixote role about static analysers. Modern C++ is safer, but only if you can ensure everyone on the team never reaches for C style tricks, nor the libraries that you link against.
- pcwalton 8y agoWhen people use the delete operator manually and mess up, do they usually delete objects too early or too late? In my experience, they usually delete objects too late or not at all (though I admit to not having hard data here). Accordingly, most of the benefits people cite regarding RAII classes such as unique_ptr are that they reduce memory leaks. I would agree that they do. But memory leaks aren't nearly as severe as use-after-free. Additionally, it's not really shared ownership that causes problems; it's the fact that references (and pointers) make it possible to violate ownership semantics. References are used all the time in C++, and you can't use any libraries without them. It doesn't matter if data has a single owner if that owner is deleted and you still hold references to the data. In fact, shared ownership via shared_ptr is safer than unique_ptr, from a UAF point of view.
- jupp0r 8y ago
- dbaupp 8y agoCan a memory leak be the root cause of memory corruption? No: there has to have been some other problem, which is why it is worth separating it from other more dangerous "safety" issues.
- htfy96 8y agoPersonal option: Separating leak from UAF and claim the former is more acceptable should not be the case, because leak applies to more than memory, and leaky fds can also create security holes like [0] [0]: https://labs.portcullis.co.uk/blog/exploiting-inherited-file-handles-in-setuid-programs/ https://labs.portcullis.co.uk/blog/exploiting-inherited-file...
- dbaupp 8y agoAccidentally "leaking" fds to a child process due to a resource leak would be a great example! However, I still feel memory/resource leaks are not the same as memory corruption. Memory corruption is more fundamental: it can be used to cause a leak, but a leak cannot be used to cause memory corruption. That is, being memory corruption-free is a necessary prerequisite for a program to also be leak-free (it isn't sufficient, though). Additionally, that example doesn't seem to be a resource leak in the sense of a memory leak. The exact same problem occurs if the file description is purposefully used after the 'system' call (that is, it isn't being leaked by not being used again). That's an issue more with 'system'/'fork' implicitly inheriting file descriptors than a resource being leaked.
- pcwalton 8y agoThis is more of an issue with setuid (which has all sorts of problems) than with leaks. Note that this issue would still occur with C++, or in any GC'd language if the GC didn't happen to run before the call to system(). Also note that Rust has contained a mitigation for that issue for a long time now: https://github.com/rust-lang/rust/pull/24034 https://github.com/rust-lang/rust/pull/24034
- htfy96 8y agoThat kind of mitigation just makes me one step away from Rust - system programming languages should stick to the platform behavior, otherwise it's just another Python. Moreover this change is not documented anywhere else. Have a look at how GLib handle these cases[0]: > - during the GSubprocess discussion, I originally held the opposite opinion, but eventually became convinced (by Colin) to see the inherit-by-default behaviour of exec() as nothing more than a questionable implementation detail of the underlying OS. Consequently, at the high level, GSubprocess provides an API that gives the caller direct control over what is inherited and what is not, and that's just the way that it should be. > - this behaviour is not limited to GSubprocess. Closing all fds before calling exec() is a common practice in modern libraries and runtimes, and for good reason. [0]: https://mail.gnome.org/archives/gtk-devel-list/2015-March/msg00038.html https://mail.gnome.org/archives/gtk-devel-list/2015-March/ms...