Master the fundamental concepts of webassembly internals through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksWASI (WebAssembly System Interface) gives Wasm modules portable syscalls: files, clocks, randomness, without baking in a JavaScript host. Runtimes like Wasmtime and Wasmer implement WASI on Linux, macOS, and Windows.
Instead of implicit full filesystem access, WASI uses capability handles passed at instantiation:
Compile with \`clang --target=wasm32-wasi\`, link with \`wasm-ld\`, run with \`wasmtime run hello.wasm\`.
For example, \`printf("hello\\n")\` lowers to WASI \`fd_write\` on the stdout capability the runtime injects at startup.
This is how Figma-scale C/C++ codebases run server-side without a browser embedding.
Preopened directories are capabilities, not global filesystem access. A module cannot open `/etc/passwd` unless the runtime explicitly grants that path at instantiation time.
This exercise asks you to document running a Wasm module under WASI. You will explain the compile flags, runtime command, and how capabilities replace browser JS imports for I/O.
You will use the same mental model here when reading production interpreter source later in the track. Sketch one concrete input on paper, predict the outcome, then confirm with code. That discipline catches logic errors early and makes debugging far faster when you extend the implementation in follow-on tasks.
Implement a small WASI host: the runtime side of wasi_snapshot_preview1 that a Wasm module calls through imports. The guest passes only integers, and all data lives in its linear memory. For example, fd_write receives a pointer to an array of iovecs ({u32 buf, u32 len}, little-endian) and writes the byte count back to a result pointer. Files are reachable only through preopened directories: WASI is capability-based, so a path is always resolved relative to a directory fd and may never escape it. Every call returns a WASI errno.
;; starts a comment. Text arguments are double-quoted, with \\n, \\t and \\" escapes.
Host setup and inspection (no guest call):
cLoading…
Guest calls:
cLoading…
badf for a closed or unknown fd, isdir for a directory, notcapable without the right, fault if an iovec or buffer lies outside memory; stdout <- "…" (or stderr) per iovec, escaped (\\n, \\", \\\\, and \\xNN for other non-printables);inval for unknown flags or neither read nor write;badf for a bad dirfd, notdir if it is not a directory;notcapable for an absolute path, or a .. that would climb above the directory. . and .. are resolved textually;isdir if the path names the directory itself;noent if the file is missing and create isn't given;fault if outside memory), and print opened HOSTPATH as fd N.badf.proc_exit(C): module exited with code C. Any later guest call prints CALL: the module has exited.cLoading…
Each call first echoes itself as shown, then prints its effects, then -> errno N (name).
Errors:
fd_write: FD IOVS IOVS_LEN OUT_PTR, path_open: DIRFD "PATH" read|write|create|trunc[,..] FD_PTR, poke: ADDR "TEXT", peek: ADDR LEN (0-64), …;cat: no host file X;unknown call X.Input:
cLoading…
Output:
cLoading…
fault, never a host crash.Hidden tests cover reads with two iovecs, rights enforcement, .. escapes and absolute paths, a path that dips into a subdirectory and back, create and trunc, a bad dirfd, a non-directory dirfd, bad flags, a double close, an out-of-bounds iovec, and calls after exit.