Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check for too many arguments to convertJsFunctionToWasm signature #16653

Closed
wants to merge 1 commit into from

Conversation

hoodmane
Copy link
Contributor

@hoodmane hoodmane commented Apr 2, 2022

Research shows that giving convertJsFunctionToWasm a signature of length > 122 triggers a compiler error like

CompileError: WebAssembly.Module(): unknown type form: 123 @+13

this puts in a more intelligible error message in this case.

@hoodmane
Copy link
Contributor Author

hoodmane commented Apr 2, 2022

To be clear, I checked that 122 is the max args on emscripten v2.0.27, so probably should double check that it hasn't changed on tot.

@kripken
Copy link
Member

kripken commented Apr 4, 2022

Which project does v2.0.27 refer to? (edit: if emscripten then that's quite old; if a browser or VM, which one?)

Which line actually throws here? (I'd guess the VM, perhaps? if so the emscripten version should not matter)

@hoodmane
Copy link
Contributor Author

hoodmane commented Apr 4, 2022

Yeah it's the VM. Can be reproduced by dumping the following into the browser console on about:blank:

Reproduction
function convertJsFunctionToWasm(func, sig) {
  if (typeof WebAssembly.Function === "function") {
    var typeNames = { i: "i32", j: "i64", f: "f32", d: "f64" };
    var type = {
      parameters: [],
      results: sig[0] == "v" ? [] : [typeNames[sig[0]]],
    };
    for (var i = 1; i < sig.length; ++i) {
      type.parameters.push(typeNames[sig[i]]);
    }
    return new WebAssembly.Function(type, func);
  }
  var typeSection = [1, 0, 1, 96];
  var sigRet = sig.slice(0, 1);
  var sigParam = sig.slice(1);
  var typeCodes = { i: 127, j: 126, f: 125, d: 124 };
  typeSection.push(sigParam.length);
  for (var i = 0; i < sigParam.length; ++i) {
    typeSection.push(typeCodes[sigParam[i]]);
  }
  if (sigRet == "v") {
    typeSection.push(0);
  } else {
    typeSection = typeSection.concat([1, typeCodes[sigRet]]);
  }
  typeSection[1] = typeSection.length - 2;
  var bytes = new Uint8Array(
    [0, 97, 115, 109, 1, 0, 0, 0].concat(
      typeSection,
      [2, 7, 1, 1, 101, 1, 102, 0, 0, 7, 5, 1, 1, 102, 0, 0]
    )
  );
  var module = new WebAssembly.Module(bytes);
  var instance = new WebAssembly.Instance(module, { e: { f: func } });
  var wrappedFunc = instance.exports["f"];
  return wrappedFunc;
}
convertJsFunctionToWasm(() => {}, "i".repeat(124))

In Chrome:

VM25:33 Uncaught CompileError: WebAssembly.Module(): unknown type form: 123 @+13
    at convertJsFunctionToWasm (<anonymous>:33:16)
    at <anonymous>:38:1

In Firefox:

Uncaught CompileError: at offset 13: expected type form
    convertJsFunctionToWasm debugger eval code:33
    <anonymous> debugger eval code:1

@hoodmane
Copy link
Contributor Author

hoodmane commented Apr 4, 2022

Yeah v2.0.27 is the Emscripten version. Pyodide is stuck on v2.0.27 because of a problem with dynamic linking in Firefox versions 96, 97, and 98 (but not 95 or 99beta) #16538

@kripken
Copy link
Member

kripken commented Apr 4, 2022

I see, thanks!

How about putting this in a try-catch around the VM command that fails? That would make it clear what the source of the issue is. We could print the VM error and also show this new warning in the case that the number of parameters is this high (maybe something like "the VM errored on trying to wrap a function. Perhaps due to too many arguments?"). That way if browsers increase the limit, things would just start to work automatically.

Also, please ifdef this behind ASSERTIONS as I think it's enough in a debug build.

@hoodmane
Copy link
Contributor Author

hoodmane commented Apr 4, 2022

Actually I think this not a platform limitation but rather a bug in convertJsFunctionToWasm that we ought to be able to fix.

@hoodmane
Copy link
Contributor Author

hoodmane commented Apr 5, 2022

Yeah so the type section generated is invalid. If I generate a valid wasm file with a 123-argument function and run wasm-objdump --debug on it I see something like:

BeginModule(version: 1)
  BeginTypeSection(128)
    OnTypeCount(1)
    OnFuncType(index: 0, params: [i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32], results: [i32])
    EndTypeSection

If I run wasm-objdump --debug on the wasm generated by convertJsFunctionToWasm for 122 argument function I see:

BeginModule(version: 1)
  BeginTypeSection(127)
    OnTypeCount(1)
    OnFuncType(index: 0, params: [i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32], results: [i32])
    EndTypeSection

If I try it on the 123 argument output I get:

BeginModule(version: 1)
  BeginTypeSection(128)
    OnTypeCount(96)
000000d: error: unexpected type form (got -0x5)

Note that it thinks there are 96 = 0x60 types. 0x60 is the prefix of a function type.
https://webassembly.github.io/spec/core/binary/types.html#function-types

@hoodmane
Copy link
Contributor Author

hoodmane commented Apr 5, 2022

Well it looks like if I put an extra 0x01 in there, it fixes it...

@hoodmane
Copy link
Contributor Author

hoodmane commented Apr 5, 2022

Aha the problem is that you aren't correctly leb128-encoding the length of the type section.

@hoodmane
Copy link
Contributor Author

hoodmane commented Apr 5, 2022

Closed in favor of #16658. It turns out the VM generates a perfectly fine error message when we give it too many arguments WebAssembly.Module(): param count of 1001 exceeds internal limit of 1000 but not when we give it bad wasm...

@hoodmane hoodmane closed this Apr 5, 2022
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.

2 participants