use virtual stdio

which works except for the lifetime issues, i think the trap still holds
an Rc to the store?
This commit is contained in:
Pat Hickey
2020-12-11 18:22:13 -08:00
parent 0572b40f58
commit 1b8f9fd377
2 changed files with 86 additions and 47 deletions

View File

@@ -2,49 +2,71 @@ use anyhow::Context;
use std::convert::TryFrom;
use std::fs::File;
use std::path::Path;
use wasi_c2::WasiCtx;
use wasi_c2::{
virt::pipe::{ReadPipe, WritePipe},
WasiCtx,
};
use wasmtime::{Linker, Module, Store};
pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> anyhow::Result<()> {
let store = Store::default();
let stdout = WritePipe::new_in_memory();
let stderr = WritePipe::new_in_memory();
// Create our wasi context with pretty standard arguments/inheritance/etc.
// Additionally register any preopened directories if we have them.
let mut builder = wasi_c2::WasiCtx::builder();
let r = {
let store = Store::default();
builder.arg(bin_name)?.arg(".")?.inherit_stdio();
// Create our wasi context.
// Additionally register any preopened directories if we have them.
let mut builder = wasi_c2::WasiCtx::builder();
if let Some(workspace) = workspace {
let dirfd =
File::open(workspace).context(format!("error while preopening {:?}", workspace))?;
let preopen_dir = unsafe { cap_std::fs::Dir::from_std_file(dirfd) };
builder.preopened_dir(Box::new(preopen_dir), ".")?;
builder
.arg(bin_name)?
.arg(".")?
.stdin(Box::new(ReadPipe::from(Vec::new())))
.stdout(Box::new(stdout.clone()))
.stderr(Box::new(stderr.clone()));
if let Some(workspace) = workspace {
let dirfd =
File::open(workspace).context(format!("error while preopening {:?}", workspace))?;
let preopen_dir = unsafe { cap_std::fs::Dir::from_std_file(dirfd) };
builder.preopened_dir(Box::new(preopen_dir), ".")?;
}
let snapshot1 = wasi_c2_wasmtime::Wasi::new(&store, builder.build()?);
let mut linker = Linker::new(&store);
snapshot1.add_to_linker(&mut linker)?;
let module = Module::new(store.engine(), &data).context("failed to create wasm module")?;
linker
.module("", &module)
.and_then(|m| m.get_default(""))
.and_then(|f| f.get0::<()>())
.and_then(|f| f().map_err(Into::into))
};
match r {
Ok(()) => Ok(()),
Err(trap) => {
let stdout = stdout
.try_into_inner()
.expect("sole ref to stdout")
.into_inner();
if !stdout.is_empty() {
println!("guest stdout:\n{}\n===", String::from_utf8_lossy(&stdout));
}
let stderr = stderr
.try_into_inner()
.expect("sole ref to stderr")
.into_inner();
if !stderr.is_empty() {
println!("guest stderr:\n{}\n===", String::from_utf8_lossy(&stderr));
}
Err(trap.context(format!("error while testing Wasm module '{}'", bin_name,)))
}
}
/*
// The nonstandard thing we do with `WasiCtxBuilder` is to ensure that
// `stdin` is always an unreadable pipe. This is expected in the test suite
// where `stdin` is never ready to be read. In some CI systems, however,
// stdin is closed which causes tests to fail.
let (reader, _writer) = os_pipe::pipe()?;
let file = reader_to_file(reader);
let handle = OsOther::try_from(file).context("failed to create OsOther from PipeReader")?;
builder.stdin(handle);
*/
let snapshot1 = wasi_c2_wasmtime::Wasi::new(&store, builder.build()?);
let mut linker = Linker::new(&store);
snapshot1.add_to_linker(&mut linker)?;
let module = Module::new(store.engine(), &data).context("failed to create wasm module")?;
linker
.module("", &module)
.and_then(|m| m.get_default(""))
.and_then(|f| f.get0::<()>())
.and_then(|f| f().map_err(Into::into))
.context(format!("error while testing Wasm module '{}'", bin_name,))
}
#[cfg(unix)]