From ea8f6945b85d5bc15854f34be93014612254adaf Mon Sep 17 00:00:00 2001 From: wan9chi Date: Sat, 11 Jul 2026 15:52:49 +0800 Subject: [PATCH] docs(fspy): document zero-initialized shared memory Document the shared-memory zero-initialization contract and verify every byte through owner and opened views. Co-authored-by: GPT-5.6 --- crates/fspy_shm/README.md | 4 +++- crates/fspy_shm/src/lib.rs | 19 +++++++++++++++++-- crates/fspy_shm/src/linux/mod.rs | 3 ++- crates/fspy_shm/src/macos/mod.rs | 4 ++-- crates/fspy_shm/src/windows/mod.rs | 4 ++-- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/crates/fspy_shm/README.md b/crates/fspy_shm/README.md index c87ee546..773be435 100644 --- a/crates/fspy_shm/README.md +++ b/crates/fspy_shm/README.md @@ -10,7 +10,7 @@ The public API is defined in [`src/lib.rs`](src/lib.rs). | API | Contract | | ----------------- | ---------------------------------------------------------------------------------- | -| `create(size)` | Creates a non-empty mapping and returns its unique owner. | +| `create(size)` | Creates a non-empty, zero-initialized mapping and returns its unique owner. | | `open(id)` | Opens another view of the mapping identified by `id`. | | `Shm::id()` | Returns the identifier to send to another process. | | `Shm::len()` | Returns the mapped size. | @@ -19,6 +19,8 @@ The public API is defined in [`src/lib.rs`](src/lib.rs). `Shm` does not synchronize memory access. The fspy channel combines it with atomic frame headers and a lock file. Senders hold a shared file lock while writing. The receiver takes the exclusive lock before reading, which waits for existing senders and rejects new ones. +Every byte in a mapping returned by `create` is initially zero. `open` exposes the mapping's current contents and does not reinitialize them. + ## Ownership semantics `create` returns the only owner. `open` returns non-owning views. diff --git a/crates/fspy_shm/src/lib.rs b/crates/fspy_shm/src/lib.rs index cd8c806f..4798b8b8 100644 --- a/crates/fspy_shm/src/lib.rs +++ b/crates/fspy_shm/src/lib.rs @@ -22,14 +22,23 @@ mod tests { // Page-aligned on all supported targets. const SIZE: usize = 64 * 1024; + // Use one byte more than 64 KiB to test multiple pages and a partial last page. + const ZERO_INITIALIZED_SIZE: usize = SIZE + 1; + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn new_mapping_is_zero_initialized_in_all_views() { + let owner = create(ZERO_INITIALIZED_SIZE).unwrap(); + let opened = open(owner.id()).unwrap(); + + assert_zero_initialized(&owner); + assert_zero_initialized(&opened); + } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn create_and_open_are_shared() { let owner = create(SIZE).unwrap(); assert_eq!(owner.len(), SIZE); assert_eq!(owner.as_ptr() as usize % align_of::(), 0); - // SAFETY: No writes occur while this slice is borrowed. - assert!(unsafe { owner.as_slice() }.iter().all(|byte| *byte == 0)); let opened = open(owner.id()).unwrap(); assert_eq!(opened.id(), owner.id()); @@ -90,6 +99,12 @@ mod tests { unsafe { shm.as_ptr().add(index).read() } } + fn assert_zero_initialized(shm: &Shm) { + assert!(shm.len() >= ZERO_INITIALIZED_SIZE); + // SAFETY: No writes occur while this slice is borrowed. + assert!(unsafe { shm.as_slice() }.iter().all(|byte| *byte == 0)); + } + fn write_byte(shm: &Shm, index: usize, value: u8) { assert!(index < shm.len()); // SAFETY: The index is in bounds and tests synchronize all accesses. diff --git a/crates/fspy_shm/src/linux/mod.rs b/crates/fspy_shm/src/linux/mod.rs index dc840141..f0abf020 100644 --- a/crates/fspy_shm/src/linux/mod.rs +++ b/crates/fspy_shm/src/linux/mod.rs @@ -17,7 +17,8 @@ pub struct Shm { _service: Option, } -/// Creates a sealed memfd mapping of `size` bytes and returns its owner. +/// Creates a zero-initialized sealed memfd mapping of `size` bytes and returns +/// its owner. /// /// The memfd is handed out to other processes by a broker task spawned onto /// the ambient tokio runtime. The broker stops on its own when the owner is diff --git a/crates/fspy_shm/src/macos/mod.rs b/crates/fspy_shm/src/macos/mod.rs index f95cf63b..ea646e1f 100644 --- a/crates/fspy_shm/src/macos/mod.rs +++ b/crates/fspy_shm/src/macos/mod.rs @@ -24,8 +24,8 @@ pub struct Shm { owner: bool, } -/// Creates a POSIX shared-memory mapping of `size` bytes and returns its -/// owner. +/// Creates a zero-initialized POSIX shared-memory mapping of `size` bytes and +/// returns its owner. /// /// # Errors /// diff --git a/crates/fspy_shm/src/windows/mod.rs b/crates/fspy_shm/src/windows/mod.rs index fbbb89bd..ec0c8cad 100644 --- a/crates/fspy_shm/src/windows/mod.rs +++ b/crates/fspy_shm/src/windows/mod.rs @@ -24,8 +24,8 @@ pub struct Shm { backing_file: Option, } -/// Creates a sparse, temporary file-backed named mapping of `size` bytes and -/// returns its owner. +/// Creates a zero-initialized, sparse, temporary file-backed named mapping of +/// `size` bytes and returns its owner. /// /// # Errors ///