brintos

brintos / hwjs-cc public Read only

0
0

coroutinize: __syscall_ret .resume traps (OOB) on the syscall error-return branch — first errno write faults #11

Open sasha opened this issue · 0 comments
S sasha commented

Summary

A coroutinized __syscall_ret faults with a WebAssembly "memory access out of bounds" the FIRST time a syscall returns an error. Its .resume clone's error branch (musl errno = -r; return -1) makes an OOB access. The success path is fine — only the error branch faults. First hit while running a self-hosted clang-22.wasm's C++ static ctors, but it should reproduce with any coroutinized program.

How to reproduce (minimal)

Compile a tiny program through the normal coroutinize flow (so __syscall_ret gets its .resume clone) that makes ONE syscall which returns an error, then run it in the browser kernel:

int main(void) { open("/no/such/file", 0); return 0; }   // open -> -1 => __syscall_ret error path

Expected: trap "memory access out of bounds" inside __syscall_ret.resume on the errno write. (Any failing syscall works: mmap(len=0)->EINVAL, etc. If a bare main() doesn't trigger it but a global ctor does, that itself is a useful signal — the first hit was from a static ctor.)

Evidence from the actual run (self-hosted clang.wasm as /init, --version)

During __wasm_call_ctors -> _GLOBAL__sub_I_WebAssemblyMCInstLower.cpp, 5 syscalls succeed then the 6th errors, and it traps on that first error return:

brk(0)->0 ; brk(0x2000)->0 ; mmap(len=0x2000)->0xF10000 ; mprotect(prot=3)->0 ; mmap(len=0, prot=3)->-22 (EINVAL) ; then TRAP

clang.__syscall_ret.resume (wasm-function[57356]) <- hwjs_resume <- hwjs_drive_loop <- __hwjs_drive <- __hwjs_ctor_drive._GLOBAL__sub_I_WebAssemblyMCInstLower.cpp <- __wasm_call_ctors RuntimeError: memory access out of bounds

Ruled out (so it's the error-branch itself, not the environment)

  • NOT memory size: identical fault at user_memory 64 MB and 768 MB, same 6th syscall.
  • NOT the stack: __stack_pointer init = 1 MiB.
  • NOT the mmap region: the returned address (15.79 MB) is inside backed memory.

Analysis / suggested direction

__syscall_ret(-22) is the first trip down the ERROR branch: errno = -r; return -1 is the first errno write of the run, and THAT access is OOB — so the bad access is in the coroutinized .resume clone of the error path (TLS/errno pointer or the coroutine frame it reads). __syscall_ret is a tiny non-suspending leaf — it likely should not be coroutinized at all; excluding it (and similar leaf libc helpers) from the pass, or fixing the error-branch lowering of the .resume clone, should unblock. First time a program of clang's scale has run under the drive, so this branch had not been exercised.