Skip to content

How can I use WASI to open a file? #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jeschkies opened this issue Dec 29, 2020 · 14 comments
Closed

How can I use WASI to open a file? #48

jeschkies opened this issue Dec 29, 2020 · 14 comments

Comments

@jeschkies
Copy link
Contributor

jeschkies commented Dec 29, 2020

Hi,

maybe there is some documentation somewhere but I just cannot figure out how to run a WASM binary from Go with wasmtime.

I compiled a Rust program to wasm with cargo wasi build --release. I want to call a method from Golang and wrote the following simple example:

package main

import (
	"fmt"
	"github.com/bytecodealliance/wasmtime-go"
)

func main() {
	engine := wasmtime.NewEngine()
	store := wasmtime.NewStore(engine)

	linker := wasmtime.NewLinker(store)

	module, err := wasmtime.NewModuleFromFile(engine, "../target/wasm32-wasi/release/bench.wasm")
	check(err)

	for _, v := range module.Imports() {
		fmt.Printf("%v ", v.Name())
	}

	wasiConfig := wasmtime.NewWasiConfig()
	wasiConfig.InheritEnv()
	wasiConfig.PreopenDir(".", ".")
	wasi, err := wasmtime.NewWasiInstance(store, wasiConfig, "wasi_unstable")
	check(err)

	err = linker.DefineWasi(wasi)
	check(err)

	instance, err := linker.Instantiate(module)
	check(err)

	nom := instance.GetExport("run_nom").Func()
	_, err = nom.Call()
	check(err)
}

func check(err error) {
	if err != nil {
        panic(err)
	}
}

It prints the required imports fd_close fd_filestat_get fd_read fd_write path_open proc_exit environ_sizes_get environ_get and the fails with the error panic: unknown import: wasi_snapshot_preview1::fd_close has not been defined. Shouldn't PreopenDir define fd_close?

How can I define the imports?

Thanks a lot 🙂

PS: I am happy to contribute with an example in the docs.

@maxmcd
Copy link

maxmcd commented Dec 29, 2020

Can you try changing this:

wasi, err := wasmtime.NewWasiInstance(store, wasiConfig, "wasi_unstable")

To this:

wasi, err := wasmtime.NewWasiInstance(store, wasiConfig, "wasi_snapshot_preview1")

I think that might do it.

@jeschkies
Copy link
Contributor Author

Thanks. Does it mean the WASM binary was compiled against wasi_snapshot_preview1?

the changed helped but now I get this

wasm trap: unreachable
wasm backtrace:
  0: 0x9661 - <unknown>!std::panicking::rust_panic_with_hook::h3a0a1147e3efaaf2
  1: 0xd6c4 - <unknown>!rust_begin_unwind
  2: 0xd873 - <unknown>!core::panicking::panic_fmt::h6bf85cafed31336d
  3: 0xcb57 - <unknown>!core::option::expect_none_failed::h7dfd2381e84fa608
  4: 0x9bd1 - <unknown>!run_nom

@maxmcd
Copy link

maxmcd commented Dec 30, 2020

Yes, I believe wasi_snapshot_preview1 is the current supported phase for rust. I think that is determined by this crate: https://github.com/bytecodealliance/wasi

Can you show your rust code? It looks like your code might be panicking on an option .unwrap with option::expect_none_failed? (or maybe something similar, not sure why it would be "expect_none".

@jeschkies
Copy link
Contributor Author

jeschkies commented Dec 30, 2020

Sure, this is the run_nom method. And I already see an .unwrap() 🙈

#[no_mangle]
pub extern "C" fn run_nom() {
    let data = std::fs::read_to_string("data/small_access.log").unwrap();
    let p = nom::CommonLogParser { input: &data };
    assert_eq!(p.count(), 161761);
}

EDIT: I changed the code to print the error failed to find a preopened file descriptor through which "data/small_access.log" could be opened.

PreopenDir has little documentation. What should the guest path be? I used . for both paths.

@maxmcd
Copy link

maxmcd commented Dec 30, 2020

Maybe better docs here: http://docs.wasmtime.dev/c-api/wasi_8h.html#a6d738a3510c5f3aa4a6f49d7bb658cd1

If you click into the Go src you can usually find which function is being called in the wasmtime C api.

Maybe try wasiConfig.PreopenDir(".", "/"), the first path is the path on the host, the second path is where the directory is mounted for wasm.

@jeschkies
Copy link
Contributor Author

Thanks for the link. Still no luck. I tried a few combinations such as wasiConfig.PreopenDir(".", "/") and wasiConfig.PreopenDir("./data", "/data"). I do get the same error when I try to use the wasmtime CLI wasmtime --dir=. target/wasm32-wasi/release/loki_bench.wasm --invoke run_nom 🤔

@maxmcd
Copy link

maxmcd commented Dec 30, 2020

Can't get it working either. Maybe it's this issue? rust-lang/rust#79199

@jeschkies
Copy link
Contributor Author

@maxmcd, thanks so much for your help. This seems to be it 🙂

@maxmcd
Copy link

maxmcd commented Dec 30, 2020

btw, in case it's unclear. I was able to get your code working by just using the parse.wasm output. Since the parse wasm binary isn't a lib it seems to work if I update nom := instance.GetExport("run_nom").Func() to be nom := instance.GetExport("_start").Func()

That then runs this code: https://github.com/jeschkies/common-log-parser-bench/blob/karsten/go/src/bin/parse.rs#L5

And finds the right file

@jeschkies
Copy link
Contributor Author

Thanks. That helped me with my original goal. I wanted to benchmark nom in WASM. How did you pass the argument to parse?

@alexcrichton
Copy link
Member

To confirm, I think everything here's been figured out? Or are there lingering questions I could help resolve?

@jeschkies
Copy link
Contributor Author

I'm not sure how to pass the main args to a WASM. However, that should be unrelated to this issue. I guess rust-lang/rust#79199 will solve this issue.

@alexcrichton
Copy link
Member

Ah yeah I believe that'll solve those issues. In that case I'll go ahead and close this issue.

@maxmcd
Copy link

maxmcd commented Jan 5, 2021

@jeschkies you might just want to use command line arguments or environment variables.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants