36 ms·
The following justifications are given: -Use-after-free, double-free, memory leaks, and other lifetime bugs are prevented at compile-time by the borrow checker
by dahfizz 6y ago
The following justifications are given:
-Use-after-free, double-free, memory leaks, and other lifetime bugs are prevented at compile-time by the borrow checker where the compiler checks ownership of data.
-Buffer overflows and other memory corruptions are prevented by compile-time and runtime bounds-checking.
-Pointer deference bugs are prevented by the absense of NULL pointers and strict ownership rules.
-Uninitialized memory is prevented because all variables and fields must be initialized.
These are all only true in safe rust. A hypervisor has to do low level things like translate memory addresses, move stack pointers around, etc. Nearly all the buggy C code, if implemented in Rust, would be wrapped in 'unsafe' and would be just as buggy.
I recommend everyone interested in Rust to take a look at how the standard library Vec is implemented[1]. The code is littered with `unsafe` - There is just no way to avoid it and do something useful at the same time.
This isn't really a shortcoming of the language, but of modern computers. It is fundamentally an unsafe operation to read or write memory, to communicate with a disk, etc. Every computer program is fundamentally unsafe. Rust does a fantastic job of making this explicit and controlling it as much as possible, but the idea that Rust code is bug free for free is just wrong.
[1] https://doc.rust-lang.org/src/alloc/vec.rs.html#300-303 https://doc.rust-lang.org/src/alloc/vec.rs.html#300-303
- estebank 6y agoI think the Vec example makes the opposite argument from the one you put forth. Vec uses unsafe internally in order to have the desiref API and performance characteristics, but it exposes a safe API. If there are bugs in the unsafe blocks that can cause UB all over the place, but it also makes it easier to audit. > There is just no way to avoid it and do something useful at the same time. I don't think that's true. Your code might have to rely on code down the abstraction layers that uses unsafe, as interacting with the hardware is inhere you unsafe, but that doesn't mean that any code you want to write won't be able to leverage the safe abstractions. The argument you're making sounds to me, and please correct me if I'm misunderstanding, that trying to create safe abstractions is sheer folly so we might as well not do so. I've been writing Rust code for years now and I've never had to write unsafe code myself other than when interacting with C code and when doing so I've found issues with the way the API the C libraries were exposing having fundamental issues.
- dahfizz 6y ago> Your code might have to rely on code down the abstraction layers that uses unsafe, as interacting with the hardware is inhere you unsafe, but that doesn't mean that any code you want to write won't be able to leverage the safe abstractions. This is the point I was trying to make by linking to the vec code. Any useful Rust program will run unsafe code. That code might just be hidden in a library. Ultimately, you are trusting that the code author did not write any bugs - in this regard you are not much safer than using the C++ stl. > The argument you're making sounds to me, and please correct me if I'm misunderstanding, that trying to create safe abstractions is sheer folly so we might as well not do so. On the contrary! I think what Rust is doing is a big step forward. But it is very important to keep in mind the limitations of a system. The authors attitude of "This is written in Rust, so it must be free of memory bugs!" is dangerous. The key benefit of Rust is to isolate and explicate the dangerous parts of your program (because there are dangerous parts!!). This should make you more vigilant of bugs, but the "Eh, the borrow checker will debug for me" attitude can often lead to programmers being less critical of their own code. Of course, none of this really applies if you are doing higher level stuff. But QEMU would definitely have to write their own 'unsafe' code.
- tedmielczarek 6y agoHere's the thing these arguments always miss: writing C/C++ is like writing your entire Rust program using unsafe. Sure, unsafe Rust code will always exist and can cause memory safety bugs. It's a lot easier to verify a few unsafe blocks in a Rust program than it is to keep all of your C++ program's invariants in your head and manually make sure you don't violate them.
- thethirdone 6y ago> These are all only true in safe rust. A hypervisor has to do low level things like translate memory addresses, move stack pointers around, etc. Nearly all the buggy C code, if implemented in Rust, would be wrapped in 'unsafe' and would be just as buggy. > I recommend everyone interested in Rust to take a look at how the standard library Vec is implemented[1]. The code is littered with `unsafe` - There is just no way to avoid it and do something useful at the same time. I think Vec is a somewhat extreme example in terms of unsafe. It requires to be able to realloc, or allocate a new buffer and move all elements; those operations do not fit into Rusts safe memory and lifetime model. If you are writing some form of container like Vec or Hashmap, I would agree with you; Rust doesn't offer much help in preventing those memory bugs. However, there is tons of other code than can be written in safe rust. Parsing binary data formats in particular is an area that can result in buggy C code and can be solved in Safe Rust. If you were referring only to the buggy code in qemu, that may very well be true. However, I would suspect there large swaths of code that don't do anything particularly interesting, but do allocate and free which Safe Rust might help with. > This isn't really a shortcoming of the language, but of modern computers. It is fundamentally an unsafe operation to read or write memory, to communicate with a disk, etc. Every computer program is fundamentally unsafe. Rust does a fantastic job of making this explicit and controlling it as much as possible, but the idea that Rust code is bug free for free is just wrong. If you trust the standard library to abide by Rust's memory invariants, you totally do unsafe operations without letting program state go into an undefined state. I don't think I have ever had a Rust program using only safe rust (in the main source code) segfault and that is simply no where close to true for C programs I have worked on and other tools I have used. The feature that I like best about the safe vs unsafe Rust is that if I only use well established libraries and only write safe rust, I can almost completely ensure my code won't segfault (even if I am incompetent). Panics are still a problem, but they are more manageable.
- anticristi 6y agoThanks for spelling this out. When I read the post I was actually wondering if there isn't a fundamental trade-off between fast and safe. A hypervisor's basic function is to add the minimum number of CPU cycles to emulate a real machine, its memory and its devices. Using safe operations, which would add a lot of cycles to do checks, would make QEMU a worse hypervisor.