The Unsafe Gate
Direct memory access is fenced behind the unsafe keyword,
keeping the risky surface of a codebase small and easy to audit.
Raw-memory operations — load/store,
changetype, memory.copy/fill/repeat,
and the v128 load/store family — are gated: using one outside an
unsafe-marked function is a compile error naming the operation.
export unsafe function peek(p: usize): i32 {
return load<i32>(p); // fine here
}
export function bad(p: usize): i32 {
return load<i32>(p); // error: load is unsafe; mark the
} // enclosing function 'unsafe'
The keyword is a review marker, not a semantic change — the generated code is identical. It makes the raw-memory surface of a codebase easy to find with a text search. The standard library is exempt, since it exists to wrap these operations.
Addresses below 1024 are reserved: nothing rasc places lives there. An
optimized build folds an address’s added constant into the access, so a
load or store whose address wraps below 1024 may
trap once optimized. load<i32>(p + 16) with p
at -8 reads address 8 in a debug build and traps in an optimized one.
A raw pointer into an object is good for one call only. Objects may move between calls, so take the pointer where you use it and never keep it in a field.