fix(lpa-fs-opfs): copy bytes before OPFS write — WebKit writes the whole buffer for wasm-memory views#117
Open
Yona-Appletree wants to merge 1 commit into
Open
fix(lpa-fs-opfs): copy bytes before OPFS write — WebKit writes the whole buffer for wasm-memory views#117Yona-Appletree wants to merge 1 commit into
Yona-Appletree wants to merge 1 commit into
Conversation
…buffer for wasm views
Root cause of the iOS Safari studio crash ("A problem repeatedly
occurred") and of every zero-filled library file: WebKit's
FileSystemWritableFileStream.write() ignores a TypedArray view's
offset/length and writes the view's ENTIRE underlying buffer (verified
on WebKit 26.5; Chrome honors the view). web-sys write_with_u8_array
passes exactly such a view over wasm linear memory, so on WebKit every
flushed file received the whole wasm heap: contents start at heap byte
0 (zeros -> "expected value at line 1 column 1"), and seeding a fresh
library serialized hundreds of MB per file -> memory spike -> iOS
jetsam -> crash loop on a fresh visit. Reproduced against production
with Playwright WebKit (iPhone profile) and pinned with a pure-JS
round-trip probe (1000-byte wasm-memory view -> 65536-byte file even
without memory growth).
Fixes:
- write_file copies into a JS-owned Uint8Array before write(); the
copy's buffer is exactly the payload, so either read interpretation
persists the right bytes. Verified byte-exact on WebKit end-to-end
(seed -> flush -> read back, all files parse, project reopens).
- load_tree skips files over 16 MiB (no legitimate package member gets
close; the only known producer is the pre-fix heap dumps). Without
this, libraries already poisoned by the old build OOM the tab again
at mount. Verified: a store with 27 x 48 MiB dumps now mounts clean.
Chrome OPFS suite: 20 tests green (2 new: exact-length round trip,
oversized-file skip).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Root cause of the iOS Safari crash loop ("A problem repeatedly occurred") on a fresh visit, and of every zero-filled library file seen so far (the
missing session: … parse meta: expected value at line 1 column 1from before):FileSystemWritableFileStream.write()ignores a TypedArray view's byteOffset/length and writes the view's entire underlying ArrayBuffer. Verified on WebKit 26.5 with a pure-JS probe: a 1000-byte view overWebAssembly.Memoryproduced a 65,536-byte file (whole wasm page), with or without memory growth. Chrome honors the view.write_with_u8_array(&[u8])passes exactly such a view over wasm linear memory. So on WebKit, every flushed file received the app's entire wasm heap: file contents start at heap byte 0 (zeros →expected value at line 1 column 1), and seeding a fresh library serialized hundreds of MB per file → memory/IO spike → iOS jetsam → crash on every visit.lightplayer.app) with Playwright WebKit (iPhone 15 Pro profile): fresh profile, click the example →skipping package dir …: manifest: parse project.json: expected value at line 1 column 1and ~1.4 GB RSS on desktop.Fixes (two layers):
write_filecopies into a JS-ownedUint8Arraybeforewrite(). The copy's buffer is exactly the payload, so both the spec-correct and the WebKit interpretation persist the right bytes.load_treeskips files over 16 MiB (library content is device-bound — kilobytes; the only known producer of bigger files is the pre-fix heap dumps). Without this, a library already poisoned by the old build re-OOMs the tab at mount even after the write fix — this is what actually un-bricks phones with existing damage.Context: PR #116 (lenient meta + husk cleanup) treated real but secondary symptoms; this is the primary defect. Consider an upstream WebKit bug report —
write()truncating BufferSource views to their view bounds is spec behavior.Validation
just lpa-fs-opfs-test): 20 tests green, including 2 new regression tests (exact-length round trip; oversized-file skip). Note the WebKit-specific behavior is not exercisable in CI's chromedriver lane — a WebKit lane is a worthwhile follow-up.just checkclean.Contribution Terms
By opening this pull request, I confirm that I have the right to submit these
changes and agree to the contribution terms in
CONTRIBUTING.md.🤖 Generated with Claude Code