Memory safety is still considered nice-to-have?
Memory safety is still considered nice-to-have?
Posted Aug 20, 2024 12:37 UTC (Tue) by tialaramex (subscriber, #21167)In reply to: Memory safety is still considered nice-to-have? by jlarocco
Parent article: FreeBSD considers Rust in the base system
std::unique_ptr<Goose> is Box<Goose>. This Goose lives on the heap somewhere, when we're done with it we need to destroy that heap allocation as well as whatever (if anything) should happen to the Goose. Both these types provide mechanisms to get the actual raw pointer out, and to convert a raw pointer back into the type, they're very parallel. It's easier to see what's going on when you Box::leak(a_goose) but the same API exists for std::unique_ptr just with a less explanatory name.
std::shared_ptr<Goose> is Arc<Goose> or in a few cases on some toolchains, magically Rc<Goose> instead -- hope the tooling was correct if that happened. There's a Goose, on the heap, and when we "duplicate" it we just get the same Goose again but we're counting how many distinct references to it exist, and once there aren't any we can get rid of the Goose. Again the APIs are parallel, std::weak_ptr is Weak<T> the most substantial difference is that C++ provides a mechanism to decide explicitly whether the control block is part of the same memory allocation. If it is, even though the std::shared_ptr<Goose> is "gone" we can't free the memory because our control block is in there, and that's needed for any remaining std::weak_ptr, but on the other hand if it isn't then we're doing a separate allocation for an item and its associated control block.
It is a problem that C++ programmers see "more modern" as safer, when it maybe isn't. For example Arc<Goose> doesn't allow multiple mutable references, but std::shared_ptr<Goose> is fine with that, and of course although programmers in C++ know they're supposed to never make mistakes they're only human, two references to the same Goose might get modified without a happens-before and now we've got a data race, it's Undefined Behaviour.
Posted Aug 20, 2024 12:57 UTC (Tue)
by khim (subscriber, #9252)
[Link] (2 responses)
Modern C++ absolutely is safer, but the big problem is that modern C++ is not a collection of modern features. Instead of being something in the language it's more of something outside of the language. Core guidelines of collection of Abseil tips or things like that. With some support from the language, sure, but mostly documents for humans. And they are pretty big. Learning them may improve robustness of your code but blind attempt of using tools designed to support these guides may easily lead to the opposite. That's the issue: unlike Rust tools that are designed to work with ignorant users C++ tools are very much not designed for that. Rust tools wouldn't withstand in the face of malicious intent (that's why they are not security tools, but safety tools) but they handle ignorance just fine. C++ doesn't handle it well.
Posted Aug 20, 2024 15:59 UTC (Tue)
by tialaramex (subscriber, #21167)
[Link] (1 responses)
You could argue they aren't _less_ safe, but even where that's true, they aren't _more_ safe, they're just more modern
For string_view in particular we know people took code that was wasteful but correct (copying strings needlessly) and converted it to code that's fragile or outright wrong through use of string_views whose underlying string might vanish while they're in use.
Posted Aug 20, 2024 16:22 UTC (Tue)
by khim (subscriber, #9252)
[Link]
No. They are safer and faster. They are combining two unrelated parts and they don't rely on zero-termination. These things already give you more safety then C counterpart.
They are not memory safe, true, but they are safer. The danger is, of course, in thinking: oh, these are modern facilities, surely they should make everything memory-safe if not abused? And no, they don't give you that kind of safety. Yes. But if you would try to convert that code into pile of raw pointers chances are that you would screw up everything even more badly. I would say that problem is not that “Modern C++” is not safer than “old C++” or “C” but that it's sold as if it's improvements in safety are comparable to what Rust offers, where in reality they are marginal at best.
Posted Aug 21, 2024 3:12 UTC (Wed)
by NYKevin (subscriber, #129325)
[Link]
C++ smart pointers are not directly analogous to Rust smart pointers, because C++ smart pointers have an empty state, and Rust smart pointers don't. This is required for C++ move semantics* to work. So all C++ smart pointers are de facto equivalent to Rust Ptr<Option<T>> (or perhaps Option<Ptr<T>>) rather than Ptr<T> (for the appropriate value of Ptr), but because C++ is unsafe, they all implicitly call unwrap_unchecked() (or as_ref().unwrap_unchecked(), etc.) every time you dereference them.
* In C++, moving an object has no effect on the original object's lifetime. A move constructor is like a copy constructor, except that it is allowed/expected to take ownership of the original object's resources. The original continues to exist until whenever it would otherwise be destroyed, and then its destructor is run if it has one. Because we don't want unique_ptr to double-free every time it is moved, we have to put it in an empty state where it won't free anything. In Rust, moving an object causes the original to magically vanish at the moment the move completes, without running the destructor at all. Well, actually there's no magic, because Rust is a systems language, so this is all well-specified and you can do it by hand in unsafe Rust. Moving an object is implemented as if by memcpy, and once the byte copy completes, the original object is "garbage" (i.e. you must not access it or otherwise interact with it, not even to run its destructor), and you may then deallocate or reuse its memory if you so desire. You can see a worked example of this in the section of the Rustonomicon where they implement Vec. In safe Rust, the compiler takes care of these details automatically, and causes it to look like the object has "magically vanished" (by the devilishly clever method of throwing a compile error if you try to interact with it after moving from it).
> It is a problem that C++ programmers see "more modern" as safer, when it maybe isn't.
Memory safety is still considered nice-to-have?
Memory safety is still considered nice-to-have?
> You could argue they aren't _less_ safe, but even where that's true, they aren't _more_ safe, they're just more modern
Memory safety is still considered nice-to-have?
Memory safety is still considered nice-to-have?
