Failed to invoke functions when running wasm file with wasmtime

1.1k views Asked by At

Mozilla shared WASI and how to use Wasmtime to run .wasm file in their blog post. The programming language they demonstrated is Rust:

#[wasm_bindgen]
pub fn render(input: &str) -> String {
    let parser = Parser::new(input);
    let mut html_output = String::new();
    html::push_html(&mut html_output, parser);
    return html_output;
}

However, I want to do the same thing in C.

I've downloaded wasi-libc and tried to build a 'hello world' program with Clang.

I created two functions in test.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int foo1()
{
    printf("Hello foo1()\n");
    return 0;
}

int foo2(char* filename)
{
    printf("Hello foo2()\n");
    printf("filename is %s\n", filename);
    return 0;
}

Build it with the command:

clang --target=wasm32-wasi --sysroot=/mnt/d/code/wasi-libc/sysroot test.c -o test.wasm -nostartfiles -Wl,--no-entry,--export=foo1,--export=foo2

Run the wasm file to invoke functions:

$ wasmtime test.wasm --invoke foo1
Hello foo1()
warning: using `--render` with a function that returns values is experimental and may break in the future
0

$ wasmtime test.wasm --invoke foo2 "hello"
warning: using `--render` with a function that takes arguments is experimental and may break in the future
error: failed to process main module `test.wasm`
    caused by: invalid digit found in string

I failed to invoke the function with an input parameter.

What's the difference between Rust and C? Is Rust currently the only way to build wasm lib file?

2

There are 2 answers

0
Till Schneidereit On

The difference is that the Rust toolchain has experimental support for Interface Types, whereas that doesn't yet exist for C, unfortunately. The #[wasm_bindgen] above the render function is what turns render into a function exported with Interface Types bindings.

0
Dbettkk On

Due to the sandboxed memory structure of Wasm, it cannot access external memory. The string you are passing here is stored in the memory of the host. For Wasm, all pointer types are represented as the offset from their base address, which is i32. So, even though you are passing a string here, Wasm Runtime will still attempt to convert it to i32 before passing it to foo2. However, Wasm Runtime cannot achieve this here. You can try using Wasmer to run it. You will get a clearer error message like this:

error: failed to run `test.wasm`
  Can't convert `hello` into a i32

If you really need to pass a string to Wasm through C, you can use the C API provided by Wasm Runtime. The specific approach is to first use the malloc function on the Wasm side to allocate a block of memory, then copy the host-side string into the memory you allocated, and finally pass the starting address of the allocated memory as a parameter to the corresponding function.