1. 19

  2. 5

    This is a great article with one exception that makes a very common error in talking about Rust. The author says:

    Blocks of code marked as unsafe are manually-designated “blindspots” for the analyses, bypassing safety-specific checks since the programmer vouches for their correctness. … unsafe drops memory safety guarantees for a limited scope and doesn’t eliminate all checks

    This is not quite correct, as Rust Core Team member Steve Klabnik’s (@steveklabnik) blog post “You can’t ‘turn off the borrow checker’ in Rust” explains. Unsafe code does not turn off the borrow checker or safety checks. What it does is allow the following operations (taken from the Rust Reference’s “Unsafety” chapter):

    • Dereferencing a raw pointer.
    • Reading or writing a mutable or external static variable.
    • Accessing a field of a union, other than to assign to it.
    • Calling an unsafe function (including an intrinsic or foreign function).
    • Implementing an unsafe trait.

    More concretely, you can have unsafe blocks, unsafe functions, and unsafe traits. Here’s an explanation, taken from the Rustonomicon’s chapter “How Safe and Unsafe Interact,” which explains:

    The unsafe keyword has two uses: to declare the existence of contracts the compiler can’t check, and to declare that a programmer has checked that these contracts have been upheld.

    You can use unsafe to indicate the existence of unchecked contracts on functions and trait declarations. On functions, unsafe means that users of the function must check that function’s documentation to ensure they are using it in a way that maintains the contracts the function requires. On trait declarations, unsafe means that implementors of the trait must check the trait documentation to ensure their implementation maintains the contracts the trait requires.

    You can use unsafe on a block to declare that all unsafe actions performed within are verified to uphold the contracts of those operations. For instance, the index passed to slice::get_unchecked is in-bounds.

    You can use unsafe on a trait implementation to declare that the implementation upholds the trait’s contract. For instance, that a type implementing Send is really safe to move to another thread.

    1. 3

      This is an excellent article. I like the explicit enumeration of what Rust gives you, and what it doesn’t, and its explicitness helps to explain why certain things that may not seem like a big deal (e.g. the Actix debacle) are actually existential risks for the assertions Rust makes. This one is going into the bookmarks.