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,17 +2,29 @@ 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 stdout = WritePipe::new_in_memory();
let stderr = WritePipe::new_in_memory();
let r = {
let store = Store::default();
// Create our wasi context with pretty standard arguments/inheritance/etc.
// Create our wasi context.
// Additionally register any preopened directories if we have them.
let mut builder = wasi_c2::WasiCtx::builder();
builder.arg(bin_name)?.arg(".")?.inherit_stdio();
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 =
@@ -21,16 +33,6 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any
builder.preopened_dir(Box::new(preopen_dir), ".")?;
}
/*
// 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);
@@ -44,7 +46,27 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any
.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,))
};
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,)))
}
}
}
#[cfg(unix)]

View File

@@ -69,31 +69,48 @@ impl WasiCtxBuilder {
pub fn build(self) -> Result<WasiCtx, Error> {
Ok(self.0)
}
pub fn arg(&mut self, arg: &str) -> Result<&mut Self, StringArrayError> {
self.0.args.push(arg.to_owned())?;
Ok(self)
}
pub fn inherit_stdio(&mut self) -> &mut Self {
pub fn stdin(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
self.0.insert_file(
0,
Box::new(crate::stdio::stdin()),
FileCaps::READ,
f,
FileCaps::READ, // XXX probably more rights are ok
FileCaps::READ,
);
self
}
pub fn stdout(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
self.0.insert_file(
1,
Box::new(crate::stdio::stdout()),
FileCaps::WRITE,
FileCaps::WRITE,
);
self.0.insert_file(
2,
Box::new(crate::stdio::stderr()),
FileCaps::WRITE,
f,
FileCaps::WRITE, // XXX probably more rights are ok
FileCaps::WRITE,
);
self
}
pub fn stderr(&mut self, f: Box<dyn WasiFile>) -> &mut Self {
self.0.insert_file(
2,
f,
FileCaps::WRITE, // XXX probably more rights are ok
FileCaps::WRITE,
);
self
}
pub fn inherit_stdio(&mut self) -> &mut Self {
self.stdin(Box::new(crate::stdio::stdin()))
.stdout(Box::new(crate::stdio::stdout()))
.stderr(Box::new(crate::stdio::stderr()))
}
pub fn preopened_dir(
&mut self,
dir: Box<dyn WasiDir>,