Furthermore, no language is “memory safe” in the absolute sense. For example, not even the borrow checker can protect you from buffer bleeds.
If one can use a use-after-free, invalid write, time of check-time of use error to write a byte to an invalid location, the program's data structures are now in an inconsistent state, violating invariants required for "spatial safety" such as objects being the correct type, buffers and lengths being paired together correctly, etc.
Likewise, if one can accomplish a buffer overflow, a spatial safety violation, or an out of bounds write, then by definition they've made temporal violations as well. Writing objects out of bounds or arbitrary heap writes imply data races.
Offensive security folks use gadgets that exploit one to accomplish the other, as needed.
[1] https://www.scattered-thoughts.net/writing/how-safe-is-zig/
Does it follow that the fact that temporal violations could be used to violate runtime spatial checks, therefore means that spatial safety in itself is entirely without value?
What are your thoughts also on buffer underflows? I ask since I take it you also work on offensive security.
To be precise, I don't think the mitigations Zig has, which the author labels as "spatial safety", are entirely without value. Optionals & sum types, range checks are helpful.
Buffer underflows as in writing to negative indices? I wish I could go in a time machine and default early languages to saturating arithmetic instead of wrapping. Even Rust does wrapping arithmetic in release mode, in debug mode overflows will panic.
Rust isn't even memory safe if you want to be THIS pedantic about it. the unsafe keyword exists in Rust, and it is often used.
Safe APIs that contain unsafe blocks must still be proven correct, via Miri, a model checker, formal proof, etc. Any safe functions that violate memory safety are considered bugs. The limited number of unsafe functions exist as helpers to build safe APIs when the compiler's borrower checker is insufficient.
What this means is that to verify memory safety, one can restrict their search to unsafe blocks. And hypothetically if the Rust compiler were to get much smarter, it should be possible to prove to the compiler that those blocks are safe (via theorem prover, perhaps?) and remove the "unsafe" declaration.
In most languages, there is no such distinction between the "memory safe" common set users ought to use and the subset that has to be verified independently. Neither Zig, C, C++, nor even Go have a clear delineation between safe and unsafe code.
That's lack of memory safety when your memory safety work is done during compilation, as is the case with Rust.
In practice, Rust seems to be much safer. I've seen Jarred talking about segfaults in Bun. Those are practically unheard of in Rust programs, and indicative of the possibility of quite serious security vulnerabilities.