Module sys/mmap

sys/mmap
Stability: unstable — the encoded-error pointer is the thing that has to go. It is valid only because no real mapping ever lands in `-1 .. -65535`, it is indistinguishable from a wild pointer to anything that forgets to call `is_error`, and it makes the return type `?*u8` while `.None` means nothing. A frozen version returns `Result(*u8, IoError)` and hands back an owning mapping type that unmaps on drop. There is also a real capability gap underneath: file mappings do not exist on wasm at all (`mmap` there always fails with `ENOSYS`), and Windows cannot partially unmap a view — `munmap`'s `length` is ignored there. — stable modules only change additively; this one may still change.

Memory-mapped I/O (mmap/munmap/mprotect/msync) — the raw syscall boundary.

No public std module maps files yet; tests/sys/mmap.test.yo (and tests/sys/advise.test.yo, which maps in order to madvise) are the only callers in this tree.

mmap cannot use the negative-errno convention the rest of std/sys uses, because its success value is a pointer. It ENCODES the error in the pointer instead — a small negative value cast to ?*u8 — so every call must be screened with is_error before the pointer is dereferenced, and error_code decodes it.

Stability

unstable — the encoded-error pointer is the thing that has to go. It is valid only because no real mapping ever lands in -1 .. -65535, it is indistinguishable from a wild pointer to anything that forgets to call is_error, and it makes the return type ?*u8 while .None means nothing. A frozen version returns Result(*u8, IoError) and hands back an owning mapping type that unmaps on drop. There is also a real capability gap underneath: file mappings do not exist on wasm at all (mmap there always fails with ENOSYS), and Windows cannot partially unmap a view — munmap's length is ignored there.

Functions

mmap function
fn(addr : ?*u8, length : usize, prot : i32, flags : i32, fd : i32, offset : i64) -> ?*u8

Map length bytes of fd starting at offset, or anonymous memory when flags includes MAP_ANONYMOUS (with fd = -1). addr is a placement hint — pass .None to let the kernel choose, which is almost always what you want. offset must be page-aligned.

The return is EITHER a live mapping OR an errno encoded as a small negative pointer: test it with is_error first and decode with error_code. Dereferencing without that check is a segfault at a low address, not a null-pointer panic.

Windows has no mmap: the runtime creates a CreateFileMappingW section sized to offset + length, maps a view of it, and closes the section handle immediately (the view keeps it alive). wasm has no file mappings at all — mmap there always fails, and error_code reports ENOSYS.

Parameters

NameTypeNotes
addr?*u8
lengthusize
proti32
flagsi32
fdi32
offseti64

Returns: ?*u8

is_error function
fn(addr : ?*u8) -> bool

Whether an mmap return is an encoded error rather than a mapping. The test is that the pointer, read as a signed integer, lies in -1 .. -65535 — a range no real mapping occupies. Call this on every mmap result before using it.

Parameters

NameTypeNotes
addr?*u8

Returns: bool

error_code function
fn(addr : ?*u8) -> i32

Decode the errno from an encoded mmap error pointer, as a POSITIVE errno (ENOMEM, EACCES, …) — note the sign differs from the rest of std/sys, which returns negated errnos. Answers 0 for a pointer that is not an encoded error, so pair it with is_error rather than testing for non-zero.

Parameters

NameTypeNotes
addr?*u8

Returns: i32

munmap function
fn(addr : *u8, length : usize) -> i32

Unmap a region previously returned by mmap. Returns 0 on success, a negative errno on failure. Any pointer into the region becomes invalid; nothing here tracks that, so this is the one call in the module that can turn a live pointer into a use-after-free.

On POSIX addr and length may name a SUBSET of a mapping, splitting it. On Windows they may not: UnmapViewOfFile releases the whole view and length is IGNORED, so partial unmapping silently unmaps everything.

Parameters

NameTypeNotes
addr*u8
lengthusize

Returns: i32

mprotect function
fn(addr : *u8, length : usize, prot : i32) -> i32

Change the protection of length bytes at addrmprotect(2). Returns 0 on success, a negative errno on failure. Both must be page-aligned; this is how a JIT flips a page from writable to executable.

On Windows this is VirtualProtect, and the runtime translates prot as though the mapping were shared and anonymous — so re-protecting a MAP_PRIVATE file view there does not get the copy-on-write protection it would on POSIX.

Parameters

NameTypeNotes
addr*u8
lengthusize
proti32

Returns: i32

msync function
fn(addr : *u8, length : usize, flags : i32) -> i32

Flush dirty pages of a MAP_SHARED mapping back to the file — msync(2). Returns 0 on success, a negative errno on failure. Without this, a mapping's writes reach the file at the kernel's convenience, so it is the durability barrier for mapped I/O the way fsync is for descriptor I/O.

flags is one of MS_ASYNC/MS_SYNC optionally with MS_INVALIDATE. Windows ignores them and always performs a FlushViewOfFile, and wasm returns -ENOSYS.

Parameters

NameTypeNotes
addr*u8
lengthusize
flagsi32

Returns: i32

Constants

PROT_NONE constant i32

PROT_NONE from <sys/mman.h> — no access at all. Useful for reserving address space, or as a guard page. Windows has no equivalent page protection for a file view, so the runtime maps read/write and then applies VirtualProtect(PAGE_NOACCESS).

Value: 0

PROT_READ constant i32

PROT_READ — pages may be read.

Value: 1

PROT_WRITE constant i32

PROT_WRITE — pages may be written. On most systems this implies readability in practice, but do not rely on it: ask for PROT_READ | PROT_WRITE when you mean both.

Value: 2

PROT_EXEC constant i32

PROT_EXEC — pages may be executed. Denied outright on hardened platforms and on Apple Silicon without the right entitlement, so treat a failure here as expected rather than exceptional.

Value: 4

MAP_SHARED constant i32

MAP_SHARED — writes go through to the underlying file and are visible to other processes mapping it. 1 on both Linux and macOS.

Value: 1

MAP_PRIVATE constant i32

MAP_PRIVATE — copy-on-write: writes are private to this process and never reach the file. 2 on both Linux and macOS.

Value: 2

MAP_ANONYMOUS constant i32

MAP_ANONYMOUS (MAP_ANON) — map zero-filled memory instead of a file; pass it with fd = -1. The value genuinely differs per platform (0x1000 on macOS, 0x20 on Linux), which is why this is a cond rather than a literal.

Value: 32

MS_ASYNC constant i32

MS_ASYNC — schedule the writeback and return immediately.

Value: 1

MS_INVALIDATE constant i32

MS_INVALIDATE — drop other mappings' cached copies of the range so they re-read from the file.

Value: 2

MS_SYNC constant i32

MS_SYNC — wait for the writeback to complete before returning. Another genuinely per-platform value (0x10 on macOS, 4 on Linux). Note that Windows ignores the flags entirely, so MS_ASYNC and MS_SYNC behave identically there (FlushViewOfFile).

Value: 4