Segregated, typed, heaps (never reuse the memory for a different type after a free) could allow similar safety.
Segregated, typed, heaps (never reuse the memory for a different type after a free) could allow similar safety.
But more generally: imagine you're making a game where you shoot a bunch of dudes, so you have a `std::Vec<Dude>` to store them, and elsewhere in the code, you reference this vec using indexes. When you shoot a dude, you want to remove it from this array, but being a programmer concerned about performance, you don't want to literally delete the entry, as that is an O(n) operation. Instead, you mark the dude as "despawned" or whatever, and then when you want to spawn a new dude, you keep a list of despawned dudes and just recreate the new dude in the same place in the array. If other places in the code are holding on to indexes to this array, the index is now invalid, but it will not be detectable: it'll just point to the wrong data, which can wreak all sorts of havoc.
This is almost exactly equivalent to "use-after-free" issues in C. In most cases, `free()` will not literally free the memory, it will mark the memory as unused and stored in a free-list, to be available for the next `malloc()` call. If you're holding on to a pointer that has been free()d, it's not that the program will segfault, it's much more insidious than that: it will point to memory that is apparently valid, but actually garbage.
This is precisely the kind of lifetime issue the Rust borrow checker was designed to solve, but by using indexes like this, you've basically just turned the borrow checker off without realizing it. If the borrow checker is intrusive enough that this becomes a very common pattern in Rust, I personally think it does serve as a pretty good counter-argument to a lot of things people say about Rust. Rust people are very quick to sing the borrow checker's praises and say that "as long as you learn to work with it, it stops becoming a problem!". If it stops becoming a problem only because you sneakily turn it off using tricks like this, maybe it's a bigger problem than people are willing to admit.
One leads to undefined behavior and is potentially exploitable in a way that allows for full control over your program's execution. That's the difference.
No one is arguing that the bug you've described isn't expressible in Rust - it obviously is. It's just not what the borrow checker is for because the borrow checker is for memory safety issues, and you're describing a logical bug.
I think this description is a very narrow way to look at memory safety (and again: totally ignoring the broader issue of lifetime safety), if I'm going to be honest. In my Rust program, I have two functions `spawnDude()` returning an index and a `despawnDude()` taking an index. In C, i have `malloc()` returning a pointer and `free()` taking a pointer. The lifetime issues are the same: just like I shouldn't `free()` a pointer twice, i shouldn't `despawnDude()` twice, and I shouldn't use a dude after I've despawned him. The implementation could even be very similar: using arenas (which is essentially what the Rust array is) and free-lists.
Again: these were the issues Rust was designed to solve, and the borrow checker is the tool it uses to solve them. And it absolutely does do that, if you use the native Rust constructs: this is the true super-power of Rust. The reason why it's so much easier to work with indexes is because you've deliberately chosen not to have the borrow checker analyze this situation. If that is something you have to do a lot of (and I've seen it a number of times, not just in the project the parent mentioned), it does say something important about how the borrow checker limits the expressive power of the language, if you have to turn it off in this way.
No. That's the end of it. The answer is no, you are wrong, that is not the case. The rest of your post is fine but irrelevant.
If this is true or at least fundamentally very close to each other, and given that exceptions can be abused for arbitrary code execution [1] [2], then it follows that Rust is no different/safer with respect to that, no?
[1] https://billdemirkapi.me/exception-oriented-programming-abus... [2] https://billdemirkapi.me/abusing-exceptions-for-code-executi...
Nope. If you're lucky, you get a segfault.
> imagine you're making a game
Actually, I would love to be making games. The benefits Rust provides aren't huge benefits in Game Dev, we get it. In fact, isn't this whole thing just a rehash of Jonathan Blow's ECS critique? But most of us aren't making games.
Imagine instead you're a not making a game, and you see CVE after CVE because of memory safety. Customer data gets stolen, things like SSNs. People's lives are impacted. I suppose a game crash is annoying, but way less annoying than someone's/my personal info being leaked.
Sure, we could go on as usual, blame "human error" and say everybody needs to do better. Or, we could accept better over perfect, and try to mitigate common errors that seem to happen often. You can still use `unsafe`. I guess by this argument, seat belts are useless, too, because they don't stop traffic fatalities completely. And so are all aviation safety improvements.
We're still here having the "Rust offers no/marginal benefits (to game dev and other niches)". Ok.
It seems to me to be a pretty unarguable point. It's frankly a bit shocking to me to see this vehement of a disagreement.
There is huge difference between the controlled and guaranteed teardown from panic in Rust and maybe segfault maybe nasal demons in C.
Rust makes this really, really difficult. If you can live with immutable pointers, you can have as many as you like, but the lifetime syntax you have to juggle can become a horror show, and can force lifetime annotations on a whole chain of structures. If you can't live with immutable references, then you are forced to use the unnecessarily ugly Rc<> syntax.
I often find myself using the array indexes trick, which leads to buggy code.
In Java, I never had to do this. Multiple "pointers" are fine. The garbage collector takes care of memory safety. In this one sense, Rust is a less-safe language than Java.
I have been writing Rust for two years now. I would not use it again if I could avoid it. It is a giant waste of time.