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:
@@ -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)]
|
||||
|
||||
@@ -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>,
|
||||
|
||||
Reference in New Issue
Block a user