unsafe code and its contractsNavigation: ← Security · Threat model
This document explains where the crate uses unsafe, why each site is sound, and how
that soundness is kept honest over time. It is a map into the authoritative artifacts — it does
not reproduce them, because they are CI-gated for drift and any copy here would rot. Notation
follows docs/notation.md.
| Artifact | What it is |
|---|---|
formal-verification/UNSAFE_INVENTORY.tsv | Every grouped unsafe source pattern in the tree: 214 rows, columns path · kind · pattern · count · contract, where kind ∈ {unsafe_block, unsafe_fn, unsafe_impl} and count records repeated identical patterns. |
formal-verification/UNSAFE_CONTRACTS.tsv | The safety contracts each pattern is bound to: 40 contracts, columns contract · scope · obligation · coverage · status · evidence, where coverage ∈ {rocq, tla, loom, miri, correspondence, compile-time, unit, trusted-boundary} and status ∈ {covered, miri-wired, trusted-boundary}. |
formal-verification/UNSAFE_BOUNDARY.md | The prose boundary map and the safety-contract matrix that ties sites to obligations. |
scripts/verify-unsafe-boundary-inventory.sh | The CI gate that keeps all of the above true. |
unsafe isunsafe is concentrated in the persistent engine; the in-memory dictionaries are almost entirely
safe Rust. By the inventory's path column:
| Region | unsafe rows | What kind |
|---|---|---|
Volatile (src/scdawg/{ascii,char}.rs) | 4 | all unsafe impl Send/Sync thread-safety assertions for the SCDAWG node handle — no raw pointers, no memory-layout unsafety |
Shared (src/substring.rs) | 2 | unsafe impl Send/Sync on a test-mock node |
Persistent (src/persistent_artrie/**) | 37 | swizzled pointers, atomic node CAS, optimistic-lock cells, raw child pointers, io_uring fixed buffers, and Send/Sync impls |
So 6 of 43 unsafe rows are outside the persistent tree, and none of those six involves raw
pointers or manual memory layout — they are all Send/Sync promises. This is the concrete basis
for the threat model's claim that the in-memory dictionaries are memory-safe by
construction (see also architecture §5).
Every inventory row names a contract, and every contract names a coverage class — the kind of evidence that discharges its proof obligation:
PointerOwnership,
BufferPageLease, the LockFree* and IoUring* models.io_uring contract), stated rather than proven.The volatile SCDAWG Send/Sync impls are in the compile-time / correspondence classes: the
handle contains no thread-hostile state, and tests/unsafe_boundary_contracts.rs exercises it under
concurrent reads.
scripts/verify-unsafe-boundary-inventory.sh is
a CI gate (a step in the formal-* jobs — see engineering/testing-strategy.md)
that makes the inventory a living contract rather than stale documentation. It:
src/**/*.rs for unsafe impl / unsafe fn / unsafe {.UNSAFE_INVENTORY.tsv (a diff -u fails on any drift) — so
adding or removing an unsafe site without updating the inventory breaks CI.src/persistent_* contract whose status is not covered or miri-wired — persistent
unsafe may not be merely asserted.The practical consequence for a contributor: you cannot add unsafe without also recording its
contract and coverage, and you cannot let the record and the code diverge. That is what lets the
threat model treat memory safety as a checked property rather than a hope.
unsafe.Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |