Skip to content

-sWASM_BIGINT generates mutually incompatible setValue/getValue() impls #17322

@sgbeal

Description

@sgbeal
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.13 (531257621816c200bc7c3be53129494afd029aec)
clang version 15.0.0 (https://github.com/llvm/llvm-project 5c6ed60c517c47b25b6b25d8ac3666d0e746b0c3)
Target: wasm32-unknown-emscripten
Thread model: posix

When building with -sWASM_BIGINT, the impls of getValue() and setValue() are inconsistent in how they handle i64 values:

  function getValue(ptr, type = 'i8') {
...
        case 'i64': return Number(HEAP64[((ptr)>>3)]);
...
    }

  function setValue(ptr, value, type = 'i8') {
...
        case 'i64': HEAP64[((ptr)>>3)] = BigInt(value); break;
...
    }

Note the Number(...) wrapper around getValue()'s impl.

That discrepancy leads to i64 return values working fine but i64 output pointer parameters (which are necessarily fetched via getValue()) to be silently mangled. That, in turn, leads to developers spending half a day scratching their head wondering why their output parameters behave differently than their return values ;). For example, from C:

int64_t foo( int64_t * arg ){
  *arg = 9007199254740991 /* == JS Number.MAX_SAFE_INTEGER */ * 2;
  return *arg;
}

will result, JS-side, in two different values for the return result and the output pointer.

The following workaround "works for me," but only because i use --post-js and thus have code-/scope-level access to overwrite getValue():

    if(Module['HEAP64']){
        const oldGetVal = getValue;
        getValue = Module['getValue'] = function(ptr,type='i8'){
            return ('i64'===type)
                ? Module['HEAP64'][ptr>>3]
                : oldGetVal(ptr,type);
        };
    }

That "works for me" with no issues so far, but having to overwrite getValue() that way is less than ideal and completely infeasible for clients who don't use --post-js to inject such a kludge.

Please consider removing the Number(...) wrapper from the i64 part of the getValue() impl. Whether or not it should be simply removed or replaced with BigInt(...) is unclear. Simply removing it works for me, but that admittedly somewhat surprises me.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions