wasmerio / wasmer-js

Monorepo for Javascript WebAssembly packages by Wasmer

Home Page:https://wasmerio.github.io/wasmer-js/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

runWasix fails, "memory import has 1 pages which is smaller than the declared initial of 17"

vexcat opened this issue · comments

Attempting to run a WASIX program using runWasix(module, {}) on @wasmer/sdk 0.6.0 fails with ok: false.

Using initializeLogger('trace'); to enable logging reveals the following:

DEBUG run_wasix_inner: wasmer_js::runtime: Initializing the global runtime
DEBUG run_wasix_inner: wasmer_js::tasks::scheduler: Spinning up the scheduler thread_id=0
DEBUG run_wasix_inner: wasmer_js::tasks::scheduler: Sending message to scheduler current_thread=0 msg=SpawnWithModule { module: Module { name: None }, task: _ }
DEBUG wait: wasmer_js::streams: Pipe closed
DEBUG wait:close: wasmer_js::streams: close
DEBUG wait: wasmer_js::instance: Closed stdin
DEBUG handle{worker.id=1}: wasmer_js::tasks::worker_message: Sending a worker message current_thread=1 msg=MarkBusy
DEBUG handle{worker.id=1}:run: wasmer_wasix::fs: Initializing WASI filesystem
DEBUG handle{worker.id=1}:run: wasmer_wasix::fs: Attempting to preopen / with alias None
DEBUG wasmer_js::tasks::scheduler: Sending message to scheduler current_thread=0 msg=WorkerBusy { worker_id: 1 }
DEBUG handle{worker.id=1}:run: wasmer::js::module: imported shared memory MemoryType { minimum: 1 pages, maximum: None, shared: false }
ERROR handle{worker.id=1}:run: wasmer_wasix::state::env: Instantiation failed pid=1 error=RuntimeError: js: WebAssembly.Instance(): Import #16 module="env" function="memory": memory import has 1 pages which is smaller than the declared initial of 17
DEBUG wasmer_js::streams: EOF
DEBUG wasmer_js::streams: EOF
DEBUG handle{worker.id=1}:run: wasmer_js::instance: Process exited unexpectedly error=Instantiation failed error.sources=[RuntimeError: js: WebAssembly.Instance(): Import #16 module="env" function="memory": memory import has 1 pages which is smaller than the declared initial of 17]
DEBUG handle{worker.id=1}:run: wasmer_js::run: close
DEBUG handle{worker.id=1}: wasmer_js::tasks::worker_message: Sending a worker message current_thread=1 msg=MarkIdle
DEBUG handle{worker.id=1}: wasmer_js::tasks::thread_pool_worker: close
 INFO wait: wasmer_js::instance: close
DEBUG wasmer_js::tasks::scheduler: Sending message to scheduler current_thread=0 msg=WorkerIdle { worker_id: 1 }

Memory import in .wasm file:

(memory $env.memory (;0;) (import "env" "memory") 17 65536 shared)

Despite this being the only memory import, MemoryType { minimum: 1 pages, maximum: None, shared: false } is logged, and wasmer attempts to initialize the module with only 1 page of memory.

Code to reproduce:

use rayon::prelude::*;
 
const NUM_THREADS: usize = 10;
 
fn thread_entry_point(id: usize) {
    println!(" in thread {}", id);
}
 
fn main() {
    let threads: Vec<_> = (0..NUM_THREADS).collect();
 
    threads.into_par_iter().for_each(|i| {
        thread_entry_point(i);
    });
}
cargo wasix build -r
import { init, runWasix, Wasmer, initializeLogger } from '@wasmer/sdk';
 
await init();
 
initializeLogger('trace');
 
let module = await WebAssembly.compileStreaming(fetch('/rayon-threads.wasm'));
 
let instance = await runWasix(module, {});
 
const { code, stdout, stderr, ok } = await instance.wait();
console.log(`Wasix exited with ${code} (${ok}): ${stdout} ${stderr}`);

Hi @vexcat, this is a known limitation and happens because the browser doesn't expose a way for finding out how many pages a WebAssembly.Memory import requires.

You can find the full explanation, code sample, and solution in the docs: Instantiation Failed Due to Memory Import Mismatch.

The solution is to give runWasix() the *.wasm file's bytes and let it handle the module compilation. We have a polyfill which will manually parse the *.wasm file and extract the information needed to properly instantiate the WebAssembly module.

const response = await fetch("/rayon-threads.wasm");
const wasm = await response.arrayBuffer();

const instance = await runWasix(wasm);
...

Hi, thanks for the response.

let wasmReq = await fetch('/rayon-threads.wasm');
let wasmArr = new Uint8Array(await wasmReq.arrayBuffer());

let instance = await runWasix(wasmArr, {});

This does not work either, failing with the same error. Maybe this is a recent regression?