> In short, if you use an unsafe block, then potentially any part of your code is unsafe.
The way I think about it is that the unsafe keyword is a promise that you’re going to maintain the safety invariants yourself, manually. The program is memory correct if it correctly maintains a certain set of invariants. Unsafe punts responsibility over those invariants to the programmer. If you use unsafe and mess up, the program may be in an invalid state. Yes - it might crash, anywhere. But the bug is still almost always in an unsafe block.
It’s often possible to make fully safe wrappers around unsafe code which maintains all those invariants manually. (Either statically or dynamically.). A lot of the rust standard library does this. For example, Vec, Box and slice all use unsafe code internally to create safe APIs.
> But the bug is still almost always in an unsafe block.
That's entirely dependent on how you write your Rust code. If you're derefing an invalid pointer then the bug is usually in how you calculated that pointer value, but the only part that actually requires 'unsafe' is the deref, not the bugged pointer calculation.
Now in properly written Rust code you should be marking all of that code as 'unsafe' in that case and documenting what invariants need to be maintained, but that's entirely on you to do. The only part the compiler actually enforces is that you mark the specific spots where you make use of the operations that 'unsafe' allows.