targets/wasm_exec.js: coerce pointer/length params to unsigned in helpers#5425
Closed
iamrajiv wants to merge 1 commit into
Closed
targets/wasm_exec.js: coerce pointer/length params to unsigned in helpers#5425iamrajiv wants to merge 1 commit into
iamrajiv wants to merge 1 commit into
Conversation
…pers Most import handlers in wasm_exec.js defensively coerce pointer and length parameters with `>>>= 0` so that values with the high bit set (common in larger WebAssembly memories where pointers exceed 2^31) are treated as unsigned rather than negative signed integers. The four internal helpers (loadValue, loadSlice, loadSliceOfValues, loadString) were the only places missing this coercion. This caused `RangeError: Start offset -X is outside the bounds of the buffer` from `new DataView(...)` (loadString) and `new Uint8Array(...)` (loadSlice) when handling large data, as reported in tinygo-org#5095. Apply the same `>>>= 0` coercion to the four helpers so they are safe regardless of how they are called. Fixes tinygo-org#5095
Contributor
Author
|
@eliasnaur thanks for the pointer i see now #5407 already added the coercion at every boundary handler which is the cleaner approach closing this sorry for the noise and thanks for taking the time to explain the rationale good signal for me on how this codebase prefers to handle these conversions |
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.
Description
Summary
Coerce pointer and length parameters in four
wasm_exec.jshelpers (loadValue,loadSlice,loadSliceOfValues,loadString) to unsigned 32-bit using>>>= 0, matching the pattern already used by every other import handler in the same file.Fixes #5095
Background
I was working on a related fix in upstream Go's
syscall/jspackage — golang/go#79148 (CL 778940,Code-Review +2, awaiting submit) — and got curious how TinyGo handles the same code paths.While reading
targets/wasm_exec.js, I noticed an inconsistency: most functions defensively coerce pointer/length params to unsigned with>>>= 0, but four internal helpers don't. Searching for an existing report I found #5095, which describes exactly this —RangeError: Start offset -X is outside the bounds of the bufferwhen WebAssembly memory pointers exceed 2^31.The bug
When WASM calls a JS import with an
i32parameter holding a uint32 value whose high bit is set (a memory pointer in the upper half of WebAssembly memory), JavaScript receives it as a negative Number. Using that signed value directly as a byte offset innew DataView(buffer, offset, len)ornew Uint8Array(buffer, offset, len)throws.Reproduction (no large allocation required — the boundary behavior is isolated):
Output:
Same
Start offset -X is outside the boundspattern as reported in #5095.Why these four helpers
Every other function in
targets/wasm_exec.jsalready does the coercion at the top of the body. Examples:fd_write,random_get,runtime.getRandomDatasyscall/js.stringVal,valueGet,valueSet,valueDelete,valueCall,valueInvokesyscall/js.copyBytesToGo,syscall/js.copyBytesToJSOnly these four were missed:
loadValue(addr)loadSlice(array, len, cap)loadSliceOfValues(array, len, cap)loadString(ptr, len)This PR applies the same
>>>= 0defensive coercion to make them safe regardless of how they're called.