wasmer-js icon indicating copy to clipboard operation
wasmer-js copied to clipboard

WASI RuntimeError occurs when loading .wasm with import other than WASI function

Open h1romas4 opened this issue 3 years ago • 6 comments

Hello.

In wasmer-js 1.0.2, WASI RuntimeError occurs when loading .wasm with import other than WASI function. This occurs when there is an (import "module" "external".

test.wasm: test.wasm.zip

(import "module" "external" (func $_ZN11chipbx_core8external17h1c65b4913beb0195E (type $t0)))
(import "wasi_snapshot_preview1" "fd_write" (func $_ZN4wasi13lib_generated22wasi_snapshot_preview18fd_write17hf61715b32291be1dE (type $t8)))
(import "wasi_snapshot_preview1" "environ_get" (func $__imported_wasi_snapshot_preview1_environ_get (type $t4)))
(import "wasi_snapshot_preview1" "environ_sizes_get" (func $__imported_wasi_snapshot_preview1_environ_sizes_get (type $t4)))
(import "wasi_snapshot_preview1" "proc_exit" (func $__imported_wasi_snapshot_preview1_proc_exit (type $t1)))

Error message:

Error: Failed to instantiate WASI: RuntimeError: `
    at B.wbg.__wbg_new_342a24ca698edd87 (/home/hiromasa/devel/amd64/chipbx/chipbx-js/node_modules/@wasmer/wasi/dist/Library.cjs.min.js:26:11276)
    at wasm://wasm/0024ee5a:wasm-function[823]:0x7c9d3
    at wasm://wasm/0024ee5a:wasm-function[79]:0x19d5a
    at s.instantiate (/home/hiromasa/devel/amd64/chipbx/chipbx-js/node_modules/@wasmer/wasi/dist/Library.cjs.min.js:26:6805)
    at file:///home/hiromasa/devel/wasm/test/src/index.mjs:18:12

test.wasm (Rust cargo build --target=wasm32-wasi --release):

fn main() {
    println!("internal: hello world!");
    unsafe { external(); }
}

#[link(wasm_import_module = "module")]
extern { fn external(); }

JavaScript (node.js):

import { init, WASI } from '@wasmer/wasi';
import * as fs from 'fs';

await init();

let wasi = new WASI({
    env: {
    },
    args: [
    ],
});

const moduleBytes = fs.readFileSync('src/test.wasm');
const module = await WebAssembly.compile(moduleBytes);
await wasi.instantiate(module, {
    'module': {
        'external': function() { console.log("external: hello world!") }
    }
});

// Run the start function
let exitCode = wasi.start();
let stdout = wasi.getStdoutString();

 // This should print "hello world (exit code: 0)"
console.log(`${stdout}(exit code: ${exitCode})`);

I think it was probably the way the imports argument was specified in wasi.instantiate. In wasmer-python, I was able to get imports in the following way. How do I do it in wasmer-js?

Python:

import os
from wasmer import engine, wasi, Store, Module, Instance, Function
from wasmer_compiler_cranelift import Compiler

#
# import function
#
def external():
    print("external: hello world!")

# read .wasm file
__dir__ = os.path.dirname(os.path.realpath(__file__))
wasm_bytes = open(__dir__ + '/test.wasm', 'rb').read()

# setup
store = Store(engine.JIT(Compiler))
module = Module(store, wasm_bytes)

# create WASI env
wasi_version = wasi.get_version(module, strict=False)
wasi_env = \
    wasi.StateBuilder('test'). \
        map_directory('the_host_current_dir', '.'). \
        finalize()
import_object = wasi_env.generate_import_object(store, wasi_version)
external_function = Function(store, external)
# register import
import_object.register(
    "module",
    {
        "external": external_function
    }
)
# create instance
instance = Instance(module, import_object)

# start
instance.exports._start()

wasmer-python result: success

internal: hello world!
external: hello world!

h1romas4 avatar Dec 15 '21 02:12 h1romas4

Can you attach here the wasm file so I can test and do a new release?

It should be supported, so I'm not sure what's happening

syrusakbary avatar Jan 25 '22 21:01 syrusakbary

Yes. It is attached to the previous post. The .wasm is the link below.

test.wasm.zip

Please let me know if there is any information that is missing. Thank you for your support.

h1romas4 avatar Jan 26 '22 06:01 h1romas4

EDIT I think this is more likely https://github.com/wasmerio/wasmer-js/issues/302

I can successfully run the wasm with Safari.


Having the similar issue here.

Error: Failed to instantiate WASI: RuntimeError: `
    at B.wbg.__wbg_new_342a24ca698edd87 (Library.esm.min.js:25:11042)
    at 0024ee5a:0x7c9d3
    at 0024ee5a:0x19d5a
    at s.instantiate (Library.esm.min.js:25:6735)
    at main (index.js:14:1)

However there's no imported modules with my case.

Here's my .wasm (compiled using WasmSwift), it should just print "42. hello.wasm.zip

The hello.wasm works fine with wasmer

> wasmer hello.wasm 
42

I use webpack 5, with buffer polyfill.

"devDependencies": {
    "buffer": "^6.0.3",
    "webpack": "^5.72.0",
    "webpack-cli": "^4.9.2"
  },
"dependencies": {
    "@wasmer/wasi": "^1.0.2"
}
//webpack.config.js
const path = require('path');
const webpack = require('webpack');

module.exports = {
    mode: 'development',
    //...
    externals: {
        'wasmer_wasi_js_bg.wasm': true
    },
    resolve: {
        fallback: {
            buffer: require.resolve('buffer/'),
        },
    },
    plugins: [
        new webpack.ProvidePlugin({
            Buffer: ['buffer', 'Buffer'],
        }),
    ]
};

YuAo avatar Apr 14 '22 16:04 YuAo

I'm running into this problem too with cura-engine and @wasmer/wasi V1.0.2

Output from the minified version (@wasmer/wasi)
Error: Failed to instantiate WASI: RuntimeError: `
    at B.wbg.__wbg_new_342a24ca698edd87 (/root/cura-engine/node_modules/@wasmer/wasi/dist/Library.cjs.min.js:26:11276)
    at wasm://wasm/0024ee5a:wasm-function[823]:0x7c9d3
    at wasm://wasm/0024ee5a:wasm-function[79]:0x19d5a
    at s.instantiate (/root/cura-engine/node_modules/@wasmer/wasi/dist/Library.cjs.min.js:26:6805)
    at main (/root/cura-engine/wasmer.js:26:21)
Output from the unminified version (@wasmer/wasi/dist/Library.cjs)
Error: Failed to instantiate WASI: RuntimeError: `
    at imports.wbg.__wbg_new_342a24ca698edd87 (/root/cura-engine/node_modules/@wasmer/wasi/dist/Library.cjs.js:880:19)
    at wasm://wasm/0024ee5a:wasm-function[823]:0x7c9d3
    at wasm://wasm/0024ee5a:wasm-function[79]:0x19d5a
    at WASI.instantiate (/root/cura-engine/node_modules/@wasmer/wasi/dist/Library.cjs.js:583:24)
    at main (/root/cura-engine/wasmer.js:26:21)

Note: the cura-engine WASM binary is quite large but I'm not sure that's what's causing this given the below reproduction. Furthermore, compiling without imported functions works fine with this library.


Minimal Reproduction

WASM Source
#include <stdio.h>
#include <stdint.h>

//Web Assembly V1 data types
typedef int32_t i32;

//Imported callback function
i32 callback(i32 num);

int main()
{
  //Print
  printf("Before\n");

  //Invoke the callback
  i32 result = callback(9+9);

  //Print
  printf("After (Result: %i)\n", result);

  return 0;
}

Note: compile with wasicc test.c -o test.wasm -Wl,--allow-undefined. Also, when I inspect the output, I see (import "env" "callback" (func $callback (type $t3))) so I'm pretty sure this is compiling correctly.

Host
//Imports
const {readFile} = require('fs/promises');
const {init, WASI} = require('@wasmer/wasi');

const main = async () =>
{
  //Initialize WASI
  await init();

  //Instantiate the WASI interface
  const wasi = new WASI({
    args: [],
    env: {},
  });

  //Read the web assembly
  const buffer = await readFile('./test.wasm');

  //Compile the web assembly
  const module = await WebAssembly.compile(new Uint8Array(buffer));

  //Instantiate the web assembly
  wasi.instantiate(module, {
    env: {
      //Callback
      callback: num =>
      {
        //Computer result
        const result = num + 5;

        //Log
        console.log(`[Callback] Invoked with ${num}, result: ${result}`);

        return result;
      }
    }
  });

  //Run the web assembly
  wasi.start();

  //Get the output
  const stdout = wasi.getStdoutString();

  //Log
  console.log(stdout);
};

main();
Output from the minified version (@wasmer/wasi)
Error: Failed to instantiate WASI: RuntimeError: `
    at B.wbg.__wbg_new_342a24ca698edd87 (/root/cura-engine/node_modules/@wasmer/wasi/dist/Library.cjs.min.js:26:11276)
    at wasm://wasm/0024ee5a:wasm-function[823]:0x7c9d3
    at wasm://wasm/0024ee5a:wasm-function[79]:0x19d5a
    at s.instantiate (/root/cura-engine/node_modules/@wasmer/wasi/dist/Library.cjs.min.js:26:6805)
    at main (/root/cura-engine/test-wasmer.js:23:8)
Output from the unminified version (@wasmer/wasi/dist/Library.cjs)
Error: Failed to instantiate WASI: RuntimeError: `
    at imports.wbg.__wbg_new_342a24ca698edd87 (/root/cura-engine/node_modules/@wasmer/wasi/dist/Library.cjs.js:880:19)
    at wasm://wasm/0024ee5a:wasm-function[823]:0x7c9d3
    at wasm://wasm/0024ee5a:wasm-function[79]:0x19d5a
    at WASI.instantiate (/root/cura-engine/node_modules/@wasmer/wasi/dist/Library.cjs.js:583:24)
    at main (/root/cura-engine/test-wasmer.js:23:8)

Workaround

Since this is a showstopper for me, I've resorted to using the experimental native wasi module. However, this doesn't work in the browser and many convenient APIs (eg: the virtual filesystem) aren't available.

Host
//Imports
const {readFile} = require('fs/promises');
const {WASI} = require('wasi');

const main = async () =>
{
  //Instantiate the WASI interface
  const wasi = new WASI({
    args: [],
    env: {},
  });

  //Read the web assembly
  const buffer = await readFile('./test.wasm');

  //Compile the web assembly
  const module = await WebAssembly.compile(new Uint8Array(buffer));

  //Instantiate the web assembly
  const instance = await WebAssembly.instantiate(module, {
    wasi_snapshot_preview1: wasi.wasiImport,
    env: {
      //Callback
      callback: num =>
      {
        //Computer result
        const result = num + 5;

        //Log
        console.log(`[Callback] Invoked with ${num}, result: ${result}`);

        return result;
      }
    }
  });

  //Run the web assembly
  wasi.start(instance);
};

main();

Note: run with the --experimental-wasi-unstable-preview1 flag.

Output
(node:32388) ExperimentalWarning: WASI is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Before
[Callback] Invoked with 18, result: 23
After (Result: 23)

Note: this is the expected output.

Wakeful-Cloud avatar May 07 '22 23:05 Wakeful-Cloud

Verified that this issue is fixed with the PR upgrading to Wasmer 3.0 wasmerio/wasmer#299 (we also added a test case to make sure it remains fixed in future releases).

We'll publish a new version soon

syrusakbary avatar Aug 30 '22 20:08 syrusakbary

~I have a .wasm file generated by the wasi sdk v16 via rust which makes use of wasi_snapshot_preview1 methods. Looking forward to a new release. In the meantime, I'll do a local build of @wasmer/wasi from main.~ Ignore this, I wasn't using the library properly. Things are working fine for me the current release.

kevinbarabash avatar Aug 31 '22 03:08 kevinbarabash