Skip to content

Fix WASM memory view invalidation when memory grows#248

Open
justjake wants to merge 2 commits intomainfrom
fix-wasm-memory-view-invalidation
Open

Fix WASM memory view invalidation when memory grows#248
justjake wants to merge 2 commits intomainfrom
fix-wasm-memory-view-invalidation

Conversation

@justjake
Copy link
Owner

@justjake justjake commented Feb 16, 2026

Summary

When Emscripten's WASM memory grows (due to -sALLOW_MEMORY_GROWTH), all existing TypedArray views become detached because the underlying ArrayBuffer is replaced. This caused bugs where reading from views after FFI calls returned undefined (in the C correctness sense) values if memory had grown during the call.

The fix introduces RefreshableTypedArray, a wrapper that lazily recreates the TypedArray view when HEAPU8.buffer changes. This uses a simple reference comparison that only triggers view recreation when actually needed.

Affected call sites:

  • runtime.ts: executePendingJobs - reads ctxPtrOut after QTS_ExecutePendingJob
  • context.ts: newPromise - reads resolve/reject handles after QTS_NewPromiseCapability
  • context.ts: getLength - reads uint32Out after QTS_GetLength
  • context.ts: getOwnPropertyNames - reads outPtr and uint32Out after QTS_GetOwnPropertyNames

Also fixed: getOwnPropertyNames was using HEAP8.buffer instead of HEAPU8.buffer

Fixes #240

Test plan

  • All 69 existing tests pass
  • Manual testing with memory-intensive workloads that trigger growth

🤖 Generated with Claude Code

When Emscripten's WASM memory grows (due to -sALLOW_MEMORY_GROWTH), all
existing TypedArray views become detached because the underlying
ArrayBuffer is replaced. This caused bugs where reading from views after
FFI calls returned undefined values if memory had grown.

The fix introduces RefreshableTypedArray, a wrapper that lazily recreates
the TypedArray view when HEAPU8.buffer changes. This is a simple reference
comparison that only triggers view recreation when actually needed.

Affected call sites:
- runtime.ts: executePendingJobs - reads ctxPtrOut after QTS_ExecutePendingJob
- context.ts: newPromise - reads resolve/reject handles after QTS_NewPromiseCapability
- context.ts: getLength - reads uint32Out after QTS_GetLength
- context.ts: getOwnPropertyNames - reads outPtr and uint32Out after QTS_GetOwnPropertyNames

Also fixed: getOwnPropertyNames was using HEAP8.buffer instead of HEAPU8.buffer

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@justjake justjake force-pushed the fix-wasm-memory-view-invalidation branch from 57ce055 to 48f9af3 Compare February 16, 2026 17:10
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.

Memory growth invalidates ctxPtrOut, causing unmanaged context creation in executePendingJobs

1 participant