6 ms·
I would say that this is an extremely narrow view of "memory safety", and totally ignores the broader concept of "lifetime safety". Yes, if the thing you want t
by OskarS 3y ago
I would say that this is an extremely narrow view of "memory safety", and totally ignores the broader concept of "lifetime safety". Yes, if the thing you want to prevent is crashes due to segfaults, indexes in Rust prevent that. But I would argue there's no practical difference between "crash due to segfault" and "panic due to index overflow" (which is definitely possible with the Rust model): both are just different ways of looking at "you dereferenced an invalid pointer". It does prevent the pointer writing into different data structures though, which is definitely an advantage of Rust (which comes with the runtime cost of bounds-checking, but that is probably worth it).
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.
- insanitybit 3y ago> But I would argue there's no practical difference between "crash due to segfault" and "panic due to index overflow 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.
- OskarS 3y agoFrom a security perspective, yes Rust is better, but it's still a security issue: if you can make a Rust program panic due to overflow, that's a DoS attack. 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.
- insanitybit 3y ago> Again: these were the issues Rust was designed to solve 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.
- 3y ago