# Memory safety is conditional on verification Let's briefly compare and contrast the philosophies of Rust and Verus with regards to memory safety. Memory safety, here, refers to a program being free of any _undefined behavior (UB)_ in its memory access. Both Rust and Verus _rely_ on memory safety being upheld; in turn, they both do a great deal to _enforce_ it. However, they enforce it in different ways. Rust's enforcement of memory safety is built around a contract between "safe" and "unsafe" code. The [first chapter of the Rustonomicon](https://doc.rust-lang.org/nomicon/safe-unsafe-meaning.html) summarizes the philosophy. In short: any "safe" code (i.e., code free of the `unsafe` keyword) must be memory safe, enforced by Rust itself via its type-checker and borrow-checker, regardless of user error. However, if any code uses `unsafe`, it is the responsibility of the programmer to ensure that the program is memory safe---and if the programmer fails to do so, then the behavior of the program is undefined (by definition). In practice, of course, most code _does_ use `unsafe`, albeit only indirectly. Most code relies on low-level utilities that can only be implemented with unsafe code, including many from the standard library (e.g., `Arc`, `RefCell`, and so on), but also from user-provided crates. In any case, the Rust philosophy is that the providers of these low-level utilities should meet a standard of "unsafe encapsulation." A programmer interacting with the library only through its safe API (and also not using `unsafe` code anywhere else) should not be able to exhibit undefined behavior, _not even by writing buggy code or using the API in an unintended way_. As such, the library implementors need to code defensively against all possible ways the client might use the safe API. When they are successful in this, the clients once again gain the guarantee that they cannot invoke UB without `unsafe` code. By contrast, Verus does not have an "unsafe/safe" distinction, nor does it have a notion of unsafe encapsulation. This is because it verifies _both_ memory safety and other forms of correctness through [Verus specifications](./requires_ensures.md). ### Example Consider, for example, the [index operation in Rust's standard `Vec` container](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.index). If the client calls this function with an index that is not in-range for the vector's length, then it is likely a bug on the part of the client. However, the index operation is part of the safe API, and therefore it must be robust to such things, and it can never attempt to read out-of-bounds memory. Therefore, the implementation of this operation has to do a bounds check (panicking if the bounds check fails). On the other hand, consider this (possible) implementation of `index` for Verus's `Vec` collection: ```rust,ignore impl Vec { #[verifier::external_body] pub fn index(&self, i: usize) -> (r: &A) requires i < self.len(), ensures *r === self[i as int], { unsafe { self.vec.get_unchecked(i) } } } ``` Unlike Rust's `index`, this implementation has no bounds checks, and it exhibits UB if called for a value of `i` that is out-of-bounds. Therefore, as ordinary Rust, it would not meet the standards of unsafe encapsulation. However, due to its `requires` clause, Verus enforces that any call to this function _will_ satisfy the contract and be in-bounds. Therefore, UB cannot occur in a _verified_ Verus program, but type-checking alone is not sufficient to ensure this. ### Conclusion Rust's concept of unsafe encapsulation means that programmers writing in safe Rust can be sure that their programs will be memory safe as long as they type-check and pass the borrow-checker, even if their code otherwise has bugs. In Verus, there is no staggered notion of correctness. If the program verifies, then it is memory safe, and it will execute according to all its specifications. If the program fails to verify, then all bets are off.