Skip to content

wasm_exec.js unsigned int problem #5095

@vladKrk

Description

@vladKrk

RangeError: Start offset is negative when processing large data in WebAssembly

Description

When working with large data in the browser, the following errors occurs:

RangeError: Start offset -2147452000 is outside the bounds of the buffer
at new DataView
at loadString
at syscall/js.stringVal
RangeError: Start offset -2018731584 is outside the bounds of the buffer
at new Uint8Array
at syscall/js.copyBytesToJS 

Root Cause

The issue occurs because WebAssembly memory pointers are unsigned 32-bit integers, but JavaScript interprets them as signed integers in certain operations. When pointers fall into the upper half of the 32-bit address space (starting from bit 2³¹), JavaScript treats them as negative numbers.

For example:

  • Unsigned representation: 2147515296 (valid address)
  • Signed representation: -2147452000 (after overflow)

This causes DataView and typed array constructors to throw a RangeError since they don't accept negative offsets.

Affected Code

The issue affects the loadString, loadValue, storeValue, loadSlice function and other places where trying to set or get uint value:

const loadString = (ptr, len) => {  
    return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len)); // <- ptr could be negative
};
const storeValue = (addr, v) => {
    let v_ref = boxValue(v);
    mem().setBigUint64(addr, v_ref, true); // <- this addr could be negavtive
}

Proposed Solution

Use the unsigned right shift operator >>> 0 to convert values to unsigned 32-bit integers:

const loadString = (ptr, len) => {  
    // Convert to unsigned 32-bit integers to handle potential negative values from WASM  
    return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr >>> 0, len >>> 0));
};

The same fix should be applied to similar functions that create typed arrays or DataViews from WASM memory:

const loadSlice = (array, len, cap) => {  
    // Convert to unsigned 32-bit integers to handle potential negative values from WASM  
    return new Uint8Array(this._inst.exports.memory.buffer, array >>> 0, len >>> 0);
};

Reproduction

  1. Load a TinyGo-compiled WebAssembly module
  2. Process data that causes memory allocation in the upper half of the 32-bit address space
  3. Call any syscall/js function that uses loadString or similar memory access functions
  4. Observe the RangeError

Environment

  • Browser: Any (Chrome, Firefox, Safari)
  • WebAssembly: TinyGo-compiled modules
  • File: wasm_exec.js (TinyGo runtime)

Related Issues

Similar issue but fix was done only for one place
#4763

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions