4 ms·
(Well-designed, first-class) GC is still the only system proven to completely remove memory safety issues. Rust comes close, but it's not RAII but the compiler-
by simiones 3y ago
(Well-designed, first-class) GC is still the only system proven to completely remove memory safety issues. Rust comes close, but it's not RAII but the compiler-enforced ownership tracking which allows for this.
C++ is very much proven to be memory unsafe in practice despite the RAII and smart pointers being part of the standard for a decade or more now. Opt-in memory safety basically just means no memory safety.
Of course, this doesn't mean that you can't create memory safe C++ programs. Probably one or two actually exist. But there also exist memory safe C programs and probably somewhere there is some memory safe program written in assembly as well.
- repelsteeltje 3y ago> (Well-designed, first-class) GC is still the only system proven to completely remove memory safety issues. To be pedantic, you need more than a GC for memory safety. Like a language (type system, bounds checks) that forces you to only look only inside the memory being managed. :-) Also, "for free" memory safety as offered by java's GC doesn't automatically guarantee resource safety. Without RAII, you still need to manage you file handles the old-fashioned manual way. Beyond that there are safety concerns that where the shared memory model managed by the GC bites you. For example: Rust solves threading issues with move semantics and pinning, guiding programmer away from shared mutable state. Also think of stop-the-world problems inherent with GCs. They can be life threatening in real-time systems. So: yes it's true that it's difficult to write safe code in C++, and many safety bugs are related to memory. But that doesn't mean that code in a GCed language is inherently safer.
- vips7L 3y ago> Also, "for free" memory safety as offered by java's GC doesn't automatically guarantee resource safety. Without RAII, you still need to manage you file handles the old-fashioned manual way Don’t you think a file handle is a completely different thing than what is normally talked about with memory safety? Can a un-closed handle let you ++ your way into remote code execution? Or reading uninitialized memory? Regardless, a GC is about trade offs. A GC alleviates the 99% of programming. Thinking about having to close a file resource occasionally, especially since javac will warn you when you don’t, is leagues easier than having to navigate the borrow checker all of the time. The same goes for concurrent programming. 99.9% of all code written in GC’d languages like Java never go over a thread boundary.
- aidenn0 3y ago> Don’t you think a file handle is a completely different thing than what is normally talked about with memory safety? Can a un-closed handle let you ++ your way into remote code execution? Or reading uninitialized memory? Unfreed memory also doesn't let you ++ your way into remote code execution. Using a file-handle after it's been closed can cause all sorts of issues; and if the underlying file-descriptor is being reused to e.g. write a shell script you can end up in RCE territory as well.
- vips7L 3y ago> Using a file-handle after it's been closed can cause all sorts of issue Is this possible in managed languages like Java? AFAIK you'll get an exception which is a bug and can cause issues, but its not a safety concern.
- kaba0 3y agoNo, you can get an exception, but that can happen either way (the OS can close the file handler irrespective of what the process does), and is not a safety violation. The only problem that can happen in managed languages is leaking of file handlers by not manually closing them, leaving it up to the GC, and opening handles faster than they are being closed — this can cause the OS to run out of handlers for the process, terminating it. But this is not a big issue in practice in my experience, in Javac try-with-resources idiomatically solves this issue.
- simiones 3y ago> To be pedantic, you need more than a GC for memory safety. Like a language (type system, bounds checks) that forces you to only look only inside the memory being managed. :-) True enough :-) > Also think of stop-the-world problems inherent with GCs. They can be life threatening in real-time systems. There are GCs that can work in real-time systems, given enough resources. RAII is also not suitable for real-time systems without much care, so the point is pretty much moot. Real-time systems require a level of attention to timing that no regular programming paradigm enables. > So: yes it's true that it's difficult to write safe code in C++, and many safety bugs are related to memory. But that doesn't mean that code in a GCed language is inherently safer. It is very much clear that programming in a GC language is safer than in C++ (or C or assembly) - not safe (the log4j vulnerability comes to mind), but absolutely and certainly safer. Rust has a radically new approach to memory safety that seems to offer similar advantages. It's still a little early (not that much internet-connected Rust-based infrastructure) to say for sure, but so far it does seem to offer similar or better safety guarantees as a GC language.
- kaba0 3y agoJava has try-with-resource blocks, though. But scope-based resource scopes are fundamentally limiting and static, it is not a generic solution. Preventing data races is cool, but it’s again, not a complete solution to the general category of race conditions, which are the real issue - and I’m not sure if there is any general enough system that could prevent it whole-sale. Also, java’s data races are well-defined (while if you mess up some unsafe logic in rust, your program is completely unpredictable from that point). Hard real time is so special that I don’t see much point bringing it up here — standard Rust/C/whatever is also not fit for that in and of itself. For soft real time, some GCs may be more than fine, the occasional frame drop won’t kill anyone for example.
- Dylan16807 3y ago> (Well-designed, first-class) GC is still the only system proven to completely remove memory safety issues. This depends on what you mean by "proven", but I don't think I agree. It's pretty easy to demonstrate that RAII without raw pointers and without multithreading is going to be unable to escape its bounds. And for C++ that includes changing the standard library so it doesn't generate pointers without checking, for example vector is entirely capable of enforcing bounds. But as you say, opting in on a per-object basis is not going to work.
- dezgeg 3y agoWhat would be your solution with regard to iterator invalidation?
- Dylan16807 3y agoThe simplest one is probably to count the number of iterators and refuse to reallocate when it's more than zero. Of course, many data structures could be adjusted so that iterators don't need to be invalidated.
- simiones 3y agoI was saying "proven" more in the sense of "battle-tested": that is, we can point to large systems people actually use which are free of memory errors, written in Java or C# or other GC languages (those with a few more memory safety features, to be fair, such as out-of-bounds checks on all containers and a memory model that doesn't allow partial reads). We don't have a single large C++ system that is free of memory issues (we do have two for C, CompCert and seL4 - but those are not manually written in C, and they took many times more work than equivalent systems without this property). Perhaps some embedded high-safety systems such as embedded medical or avionics devices would qualify, but those are not public so it's hard to be sure. So yes, theoretically you can build a complex system with a subset of C++ that is safe. Bjarne Stroustrup has explicitly defined such a subset for use in avionics and other military applications, even before many of the more modern C++ features. But there is little proof that this system can actually be successfully be deployed in most organizations. I'd also note "without multi threading" is such a huge limitation that it immediately moves your proposed system to toy language territory in my book. And even adding shared memory multi-process collaboration (e.g. mmap() ) would not be safe.