Skip to content

Bump napi: fix the V8+WASIX large-payload leak and the host-heap corruption abort - #143

Open
Arshia001 wants to merge 4 commits into
mainfrom
fix/v8-large-payload-leak
Open

Bump napi: fix the V8+WASIX large-payload leak and the host-heap corruption abort#143
Arshia001 wants to merge 4 commits into
mainfrom
fix/v8-large-payload-leak

Conversation

@Arshia001

@Arshia001 Arshia001 commented Aug 10, 2026

Copy link
Copy Markdown
Member

Submodule bumps only. Picks up three napi changes covering two independent bugs on the V8/N-API WASIX lane plus the API cleanup that came out of reviewing them. quickjs is unaffected by any of it.

1. Guest-heap chunk allocators leaked ~2 MiB of host metadata per 1 MiB chunk (wasmerio/napi#53). Every GuestHeap chunk built its offset allocator with Allocator::new, which sizes the node arena for 128Ki allocations no matter how small the chunk is. Chunks are claimed as a workload's peak grows and never released, so host RSS grew about three times the guest memory being managed. On the payload load test (echo-buffer, 10 MiB bodies, 1.95 GiB moved), net RSS growth drops 368 MB -> 134 MB and host-anonymous growth drops ~20 MB/GiB -> ~1 MB/GiB.

2. The external-backing-store hint set was mutated from V8's ArrayBufferSweeper background threads (wasmerio/napi#53) with no synchronization against the main thread, corrupting the host heap. The runtime aborted with malloc_consolidate(): unaligned fastbin chunk detected a few hundred requests into a payload-heavy workload. With a config that reproduces it, 2 of 6 runs died before the fix and 0 of 28 after.

3. GuestHeap no longer reaches into wasmer's private VM types (wasmerio/napi#54). It was holding a VMSharedMemory obtained through an accessor that returned an unnameable type and panicked on non-sys backends; it now uses the store-free SharedMemory::grow/data_ptr/style API added in wasmerio/wasmer#6877.

Merge order

This branch's napi pin is the head of wasmerio/napi#54, so:

  1. Fix the V8+WASIX large-payload memory leak and the host-heap corruption abort napi#53
  2. Reach the guest memory through SharedMemory instead of the VM handle napi#54
  3. feat(api): let embedders grow a shared memory without a store wasmer#6877 (its napi pin is wasmer run edgejs.wasm crashes when exitting #54's head too)
  4. this PR

wasmerio/wasmer#6877 replaces the previous ten-PR chore: bump napi stack (#6819-#6850), which has been closed.

Testing

Verified locally against this branch's napi pin, built into a wasmer CLI with --features napi-v8,llvm:

  • 38/38 wasmer-napi lib tests green (2 new).
  • Payload load test, 150 rounds / ~15 GiB: linear-memory claims converge — 72 chunks total, 66 of them in the first 25 rounds, then 2/2/0/1 per subsequent 25-round block.
  • Separate 150-round / 29.3 GiB run: total RSS growth fits a logarithmic curve 2.4x better than linear, i.e. a converging high-water rather than a leak.
  • Post-refactor re-verification: 20 rounds / 3.91 GiB verified byte-for-byte with flat per-round retention, and 8/8 clean abort-trial runs.

Note for reviewers

For the v8-wasix CI lane to actually exercise any of this, the WASMER_SOURCE_REF repo var needs to point at a wasmer build carrying wasmerio/wasmer#6877 — otherwise the lane builds the runtime with wasmer main's older napi pin and tests none of these fixes.

…o the chunk

Fixes the dominant term in the V8+WASIX large-payload leak — each 1 MiB guest
chunk was costing ~2 MiB of permanently-retained host allocator metadata.
Picks up the fix for the host-heap corruption that aborted edgejs-v8 with
"malloc_consolidate(): unaligned fastbin chunk detected" under sustained load:
V8's ArrayBufferSweeper background threads were mutating the env's hint
unordered_set concurrently with the main thread.
… handle

Picks up wasmerio/napi#54, which replaces the private-VM-type accessor
GuestHeap was using with the store-free SharedMemory::grow/data_ptr/style
API added in wasmerio/wasmer#6877. Removes an unwrap_sys_ref() that would
panic on the v8/js backends, and the last unsafe deref on the grow path.
wasmerio/wasmer#6848 ("port to vanilla Wild and use in-memory FS") removed
the lib/wild submodule. provision-wasmer.sh asked for it unconditionally, so
checking out any wasmer ref at or after that commit died with

    error: pathspec 'lib/wild' did not match any file(s) known to git

before a single thing was built, taking every lane that provisions wasmer
with it. Guard the init on the path actually being in the tree, which keeps
older refs (which do need it, since wasmer-compiler path-depends on
wasmer-wild at lib/wild/libwild) working unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant