The same for "NULL pointer dereference"; the Rust equivalent (without using raw pointers, which require "unsafe") is calling .unwrap() on an Option<T> which has a None, which once again is not prevented at compile time, only converted into a panic at run time.
Edit: note, however, that idiomatic Rust can help prevent these bugs, by using iterators instead of indexed access, and match/if-let statements instead of unwrap/expect.
Drivers by their very nature require a lot of unsafe pointer passing...Having worked on a lot of embedded Linux driver code, I'm not convinced that you could do without a ton of unsafe code...which basically negates all of Rust's safety guarantees...The current architecture just doesn't lend itself well to Rust (in my opinion), so you would have to basically rewrite very large parts of the plumbing, which by its very nature would introduce a ton of new bugs...
Drivers are a fundamentally unsafe concept, like an ffi call, you're talking to hardware the compiler doesn't understand and assuming it's going to do what you want. So there will of course be some unsafe. In a well implemented driver it will also be very limited in scope and relatively easy to check.
I can't vouch for the code quality (I just don't know how good it is, I had no hand in writing it, and it's not used in a production system), but I believe you can find a usb driver implementation written in rust here: https://gitlab.redox-os.org/redox-os/drivers/-/tree/master/x...
I'm sure that is what the C developer thought as well...I'm not trying to be snarky, but that same arguments that are made against C code holds equally true for unsafe code...
I don't think it is a reasonable position to suggest that unsafe Rust code is somehow safer than C code...
You can limit what comes in from safe rust.
Unsafe rust still has more compiler checks than C. Unsafe rust is not as permissive as C. Its rust still, with certain things permitted.
Its unsafe{} not nosafe{}
The idea is that you build an abstraction and wrap away the unsafety. That abstraction has to be built defensively, which is enabled by the type system enforcing very powerful invariants across the program. You can safely encode the way your structures may or may not be used across threads, enforce exclusive vs shared access, control mutability.
Unsafe is not a "do whatever" card, you use it with the rest of the language as one more tool that helps build safe programs.