wasmerio / wasmer-js

Monorepo for Javascript WebAssembly packages by Wasmer
https://wasmerio.github.io/wasmer-js/
MIT License
946 stars 83 forks source link

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

Closed vexcat closed 10 months ago

vexcat commented 10 months ago

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}`);
linear[bot] commented 10 months ago

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

Michael-F-Bryan commented 10 months ago

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);
...
vexcat commented 10 months ago

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?

argenisleon commented 4 months ago

@vexcat did you solve this? Getting the same problem @Michael-F-Bryan

Michael-F-Bryan commented 4 months ago

Unfortunately, I left Wasmer at the end of January and am no longer working on any Wasmer projects. @syrusakbary should be able to help you, though.

CosmicGummy commented 3 months ago

I ran into the same issue. Building wasmer-js locally solved it for me. Perhaps the package needs to be updated on npm?

syrusakbary commented 3 months ago

Hey @vexcat, @argenisleon we are upgrading the SDK on this PR: https://github.com/wasmerio/wasmer-js/pull/424

Let me know if using wasmer-js from the branch solves things for you

CosmicGummy commented 3 months ago

It looks like I modified something in my cache at some point, which is why it appeared a local build worked for me. I was able to reproduce the issue with a fresh cache, and with the npm rc from yesterday.

It looks like the problem is From<WebAssembly::Module> for Module removes type hints in wasmer here.

That's called from From<WebAssembly::Module> for crate::module::Module here, which is called when spawning a task with a module here.

runWasix spawns a task with a module here.

If you inspect module in src/run.rs on lines 43 and 50, you'll see the type hints and name after creating the wasmer::Module on 43, but not inside on the task on 50.