From 48d0b7686bf65b7325e20c817c57b559075fe629 Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Thu, 3 Oct 2024 08:24:47 -0600 Subject: [PATCH] Ch. 20: Fix safety handling in the `static mut` example - Add `SAFETY` documentation on the unsafe function and comments on the unsafe invocation in the code samples. - Discuss the soundness issues in more depth and explain the idiomatic use of those `SAFETY` comments. --- .../listing-20-10/src/main.rs | 15 ++++++++------- src/ch20-01-unsafe-rust.md | 10 +++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/listings/ch20-advanced-features/listing-20-10/src/main.rs b/listings/ch20-advanced-features/listing-20-10/src/main.rs index b5559fd3a5..360e3548fc 100644 --- a/listings/ch20-advanced-features/listing-20-10/src/main.rs +++ b/listings/ch20-advanced-features/listing-20-10/src/main.rs @@ -1,15 +1,16 @@ static mut COUNTER: u32 = 0; -fn add_to_count(inc: u32) { - unsafe { - COUNTER += inc; - } +/// SAFETY: Calling this from more than a single thread at a time is undefined +/// behavior, so you *must* guarantee you only call it from a single thread at +/// a time. +unsafe fn add_to_count(inc: u32) { + COUNTER += inc; } fn main() { - add_to_count(3); - unsafe { - println!("COUNTER: {COUNTER}"); + // SAFETY: This is only called from a single thread in `main`. + add_to_count(3); + println!("COUNTER: {}", COUNTER); } } diff --git a/src/ch20-01-unsafe-rust.md b/src/ch20-01-unsafe-rust.md index 660135cab2..e559f46dc8 100644 --- a/src/ch20-01-unsafe-rust.md +++ b/src/ch20-01-unsafe-rust.md @@ -402,7 +402,15 @@ As with regular variables, we specify mutability using the `mut` keyword. Any code that reads or writes from `COUNTER` must be within an `unsafe` block. This code compiles and prints `COUNTER: 3` as we would expect because it’s single threaded. Having multiple threads access `COUNTER` would likely result in data -races. +races, so it is undefined behavior. Therefore, we need to mark the entire +function as `unsafe`, and document the safety limitation, so anyone calling the +function knows what they are and are not allowed to do safely. + +Whenever we write an unsafe function, it is idiomatic to write a comment +starting with `SAFETY` and explaining what the caller needs to do to call the +function safely. Likewise, whenever we perform an unsafe operation, it is +idiomatic to write a comment starting with `SAFETY` to explain how the safety +rules are upheld. With mutable data that is globally accessible, it’s difficult to ensure there are no data races, which is why Rust considers mutable static variables to be