Stream: git-wasmtime

Topic: wasmtime / issue #6115 Weird behavior - when trying to in...


view this post on Zulip Wasmtime GitHub notifications bot (Mar 28 2023 at 23:29):

NeoTech opened issue #6115:

Given this code - taken out of the example and slightly modified.

use anyhow::Ok;
use wasmtime::*;

struct MyState {
  name: String,
  count: usize,
}

fn main() -> Result<()> {
  let engine = Engine::default();
  let module = Module::from_file(&engine, "wasm-module/target/wasm32-wasi/debug/wasm-module.wasm")?;
  let mut store = Store::new(
    &engine,
    MyState {
        name: "Add one".to_string(),
        count: 0,
    },
);
let add_one_func = Func::wrap(&mut store, |mut caller: Caller<'_, MyState>| {
  println!("Calling back...");
  println!("> {}", caller.data().name);
  caller.data_mut().count += 1;
});

let imports = [add_one_func.into()];
let instance  = Instance::new(&mut store, &module, &imports)?;
let run: TypedFunc<i32, i32>  = instance.get_typed_func(&mut store, "add_one")?;

let _ = run.call(&mut store, 1);

Ok(())
}

And running a wasm32-wasi compiled binary created with this rust file.

/*
    This compiles with wasm32-wasi.
    It will export a function named "run" that can be called from the host.
    It will fail to run in a wasm runtime that doesn't support the wasi target.
*/

#![allow(dead_code)]
#![allow(unused_variables)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    Ok(())
}

#[export_name="run"]
pub fn run() {
    println!("Hello, world!");
}

#[export_name="add_one"]
pub fn add_one(x: i32) -> i32 {
    x + 1
}

using the command cargo build --target wasm32-wasi

I get this error:
Error: expected 4 imports, found 1

Looking in the code WAT, i find this:

  (import "wasi_snapshot_preview1" "fd_write" (func $_ZN4wasi13lib_generated22wasi_snapshot_preview18fd_write17h49bd8e13f92c4698E (type 7)))
  (import "wasi_snapshot_preview1" "environ_get" (func $__imported_wasi_snapshot_preview1_environ_get (type 1)))
  (import "wasi_snapshot_preview1" "environ_sizes_get" (func $__imported_wasi_snapshot_preview1_environ_sizes_get (type 1)))
  (import "wasi_snapshot_preview1" "proc_exit" (func $__imported_wasi_snapshot_preview1_proc_exit (type 0)))

And i expect those to be there.. but wasmtime runtime - does not.. And i cannot really add the to the import either was they are system calls - they are supposed to be there.

I don't understand if this is a expected behavior? Or if this is a bug.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 29 2023 at 01:40):

pchickey commented on issue #6115:

Your application expects wasi (and will need it if you want to see your println work), but you didn't provide a wasi implementation to wasmtime. You can provide a wasi implementation via https://docs.rs/wasmtime-wasi/latest/wasmtime_wasi/sync/fn.add_to_linker.html, though you'll have to switch from manually providing the imports as a list to using a Linker https://docs.rs/wasmtime/latest/wasmtime/struct.Linker.html.

Additionally: you are defining add_one inside your webassembly module, so nothing in there is going to call out to the add_one_func you defined for Wasmtime.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 29 2023 at 01:42):

pchickey edited a comment on issue #6115:

Your application expects wasi (and will need it if you want to see your println work), but you didn't provide a wasi implementation to wasmtime. You can provide a wasi implementation via https://docs.rs/wasmtime-wasi/latest/wasmtime_wasi/sync/fn.add_to_linker.html, though you'll have to switch from manually providing the imports as a list to using a Linker https://docs.rs/wasmtime/latest/wasmtime/struct.Linker.html.

Additionally: you are defining add_one inside your webassembly module, so nothing in there is going to call out to the add_one_func you defined for Wasmtime. If you want to call out to that host func you will need to define it like

extern "C" {
  fn add_one(i32) -> i32;
}

view this post on Zulip Wasmtime GitHub notifications bot (Mar 29 2023 at 06:51):

NeoTech commented on issue #6115:

So this little tinker; #[export_name="add_one"]
Is supposed to solve the extern "C" thingy for you.
As it works with the wasmer commandline client just fine - not sure why this would reuireuiq the extern "C" mapping?!

will dig into the linker instead. Bare in mind, this is example code copied from the wasmtime documentation in the first field.
And the second one is just a simple wasm32-wasi compiled file i used a testing ground in all the other wasi runtimes i tested out.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 29 2023 at 08:25):

bjorn3 commented on issue #6115:

#[export_name] exports an item from the wasm module to the host. You need extern "C" {} to import an item from the host to the wasm module.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 29 2023 at 08:31):

NeoTech commented on issue #6115:

So why does this work?

use anyhow::Result;
use wasmtime::*;
use wasmtime_wasi::sync::WasiCtxBuilder;

fn main() -> Result<()> {
    // Define the WASI functions globally on the `Config`.
    let engine = Engine::default();
    let mut linker = Linker::new(&engine);
    wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;

    // Create a WASI context and put it in a Store; all instances in the store
    // share this context. `WasiCtxBuilder` provides a number of ways to
    // configure what the target program will have access to.
    let wasi = WasiCtxBuilder::new()
        .inherit_stdio()
        .inherit_args()?
        .build();
    let mut store = Store::new(&engine, wasi);

    // Instantiate our module with the imports we've created, and run it.
    let module = Module::from_file(&engine, "wasi-hello-wasm/target/wasm32-wasi/debug/wasi-hello.wasm")?;
    linker.module(&mut store, "", &module)?;
    linker
        .get_default(&mut store, "")?
        .typed::<(), ()>(&store)?
        .call(&mut store, ())?;

    Ok(())
}

With the wasm module compiled from this. - This does not have an export tho and just relies on main..
If i wanted to export the add function, and execute it outside of main - how would you rewrite this example?!

fn main() {
    println!("Hello, world!");
    println!("{}", add(5, 8));
}

fn add(a: i32, b: i32) -> i32 {
    a + b
}

view this post on Zulip Wasmtime GitHub notifications bot (Mar 29 2023 at 08:47):

bjorn3 commented on issue #6115:

In your initial example it seemed like you were trying to import add_one, but the code you wrote exports add_one. If you actually wanted to export it, then your code is correct, but you need to switch from the bin to cdylib crate type. The bin crate type only exports the main function.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 29 2023 at 11:40):

NeoTech commented on issue #6115:

Thanks, that makes alot more sense now to me.. :)

view this post on Zulip Wasmtime GitHub notifications bot (Mar 29 2023 at 11:40):

NeoTech closed issue #6115:

Given this code - taken out of the example and slightly modified.

use anyhow::Ok;
use wasmtime::*;

struct MyState {
  name: String,
  count: usize,
}

fn main() -> Result<()> {
  let engine = Engine::default();
  let module = Module::from_file(&engine, "wasm-module/target/wasm32-wasi/debug/wasm-module.wasm")?;
  let mut store = Store::new(
    &engine,
    MyState {
        name: "Add one".to_string(),
        count: 0,
    },
);
let add_one_func = Func::wrap(&mut store, |mut caller: Caller<'_, MyState>| {
  println!("Calling back...");
  println!("> {}", caller.data().name);
  caller.data_mut().count += 1;
});

let imports = [add_one_func.into()];
let instance  = Instance::new(&mut store, &module, &imports)?;
let run: TypedFunc<i32, i32>  = instance.get_typed_func(&mut store, "add_one")?;

let _ = run.call(&mut store, 1);

Ok(())
}

And running a wasm32-wasi compiled binary created with this rust file.

/*
    This compiles with wasm32-wasi.
    It will export a function named "run" that can be called from the host.
    It will fail to run in a wasm runtime that doesn't support the wasi target.
*/

#![allow(dead_code)]
#![allow(unused_variables)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    Ok(())
}

#[export_name="run"]
pub fn run() {
    println!("Hello, world!");
}

#[export_name="add_one"]
pub fn add_one(x: i32) -> i32 {
    x + 1
}

using the command cargo build --target wasm32-wasi

I get this error:
Error: expected 4 imports, found 1

Looking in the code WAT, i find this:

  (import "wasi_snapshot_preview1" "fd_write" (func $_ZN4wasi13lib_generated22wasi_snapshot_preview18fd_write17h49bd8e13f92c4698E (type 7)))
  (import "wasi_snapshot_preview1" "environ_get" (func $__imported_wasi_snapshot_preview1_environ_get (type 1)))
  (import "wasi_snapshot_preview1" "environ_sizes_get" (func $__imported_wasi_snapshot_preview1_environ_sizes_get (type 1)))
  (import "wasi_snapshot_preview1" "proc_exit" (func $__imported_wasi_snapshot_preview1_proc_exit (type 0)))

And i expect those to be there.. but wasmtime runtime - does not.. And i cannot really add the to the import either was they are system calls - they are supposed to be there.

I don't understand if this is a expected behavior? Or if this is a bug.


Last updated: Nov 22 2024 at 17:03 UTC