Skip to content

Commit efc842e

Browse files
authored
Merge pull request #1325 from Phala-Network/fd_write
sidevm: Allow writing to stdout and stderr
2 parents cef1fce + f262ac9 commit efc842e

File tree

5 files changed

+105
-11
lines changed

5 files changed

+105
-11
lines changed

crates/sidevm/host-runtime/src/env.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,17 @@ impl Env {
336336
pub fn is_stifled(&self, store: &mut impl AsStoreMut) -> bool {
337337
self.inner.lock().unwrap().is_stifled(store)
338338
}
339+
340+
pub fn memory(&self) -> Memory {
341+
self.inner
342+
.lock()
343+
.unwrap()
344+
.memory
345+
.0
346+
.as_ref()
347+
.expect("BUG: missing memory in env")
348+
.clone()
349+
}
339350
}
340351

341352
impl<'a, 'b> env::OcallEnv for FnEnvMut<'a, &'b mut EnvInner> {

crates/sidevm/host-runtime/src/env/wasi_env.rs

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ use super::{Env as WasiEnv, Result};
22
use libc::{clock_getres, clock_gettime, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME};
33
use sidevm_env::{OcallError, OcallFuncs};
44
use thiserror::Error;
5+
use tracing::{error, info};
56
use wasmer::{
6-
namespace, AsStoreMut, Exports, Function, FunctionEnv, FunctionEnvMut, Memory32, WasmPtr,
7+
namespace, AsStoreMut, Exports, Function, FunctionEnv, FunctionEnvMut, Memory32,
8+
MemoryAccessError, WasmPtr,
79
};
810
use wasmer_wasix_types::{
911
types::*,
@@ -34,6 +36,43 @@ macro_rules! wasi_try {
3436
}};
3537
}
3638

39+
/// Like the `try!` macro or `?` syntax: returns the value if the computation
40+
/// succeeded or returns the error value. Results are wrapped as an `Ok(errno)`.
41+
macro_rules! wasi_try_ok {
42+
($expr:expr) => {{
43+
let res: Result<_, Errno> = $expr;
44+
match res {
45+
Ok(val) => val,
46+
Err(err) => {
47+
return Ok(err);
48+
}
49+
}
50+
}};
51+
}
52+
53+
/// Like `wasi_try` but converts a `MemoryAccessError` to a `wasi::Errno`.
54+
macro_rules! wasi_try_mem_ok {
55+
($expr:expr) => {{
56+
wasi_try_ok!($expr.map_err(mem_error_to_wasi))
57+
}};
58+
}
59+
60+
/// Like `wasi_try` but allow the inner block to use `?` syntax on a Result<_, Errno>.
61+
macro_rules! wasi_try_block_ok {
62+
($expr:expr) => {{
63+
wasi_try_ok!(|| -> Result<_, Errno> { Ok($expr) }())
64+
}};
65+
}
66+
67+
fn mem_error_to_wasi(err: MemoryAccessError) -> Errno {
68+
match err {
69+
MemoryAccessError::HeapOutOfBounds => Errno::Memviolation,
70+
MemoryAccessError::Overflow => Errno::Overflow,
71+
MemoryAccessError::NonUtf8String => Errno::Inval,
72+
_ => Errno::Unknown,
73+
}
74+
}
75+
3776
pub(crate) fn wasi_imports(store: &mut impl AsStoreMut, env: &FunctionEnv<WasiEnv>) -> Exports {
3877
namespace! {
3978
"args_get" => Function::new_typed_with_env(store, env, args_get),
@@ -353,14 +392,55 @@ pub fn fd_tell(
353392
Errno::Nosys
354393
}
355394

395+
#[tracing::instrument(skip_all, fields(fd = fd))]
356396
pub fn fd_write(
357-
_env: FunctionEnvMut<WasiEnv>,
358-
_fd: wasi::Fd,
359-
_iovs: WasmPtr<__wasi_ciovec_t<Memory32>>,
360-
_iovs_len: u32,
361-
_nwritten: WasmPtr<u32>,
362-
) -> Errno {
363-
Errno::Success
397+
ctx: FunctionEnvMut<WasiEnv>,
398+
fd: wasi::Fd,
399+
iovs: WasmPtr<__wasi_ciovec_t<Memory32>>,
400+
iovs_len: u32,
401+
nwritten: WasmPtr<u32>,
402+
) -> Result<Errno, WasiError> {
403+
if fd != 1 && fd != 2 {
404+
return Ok(Errno::Badf);
405+
}
406+
fd_write_stdio(ctx, fd, iovs, iovs_len, nwritten)
407+
}
408+
409+
fn fd_write_stdio(
410+
ctx: FunctionEnvMut<'_, WasiEnv>,
411+
fd: wasi::Fd,
412+
iovs: WasmPtr<__wasi_ciovec_t<Memory32>>,
413+
iovs_len: u32,
414+
nwritten: WasmPtr<u32>,
415+
) -> Result<Errno, WasiError> {
416+
let env = ctx.data();
417+
let memory = env.memory();
418+
let memory = memory.view(&ctx);
419+
let iovs_arr = wasi_try_mem_ok!(iovs.slice(&memory, iovs_len));
420+
let iovs_arr = wasi_try_mem_ok!(iovs_arr.access());
421+
let mut written = 0usize;
422+
for iovs in iovs_arr.iter() {
423+
let buf = wasi_try_block_ok! {
424+
WasmPtr::<u8>::new(iovs.buf)
425+
.slice(&memory, iovs.buf_len)
426+
.map_err(mem_error_to_wasi)?
427+
.access()
428+
.map_err(mem_error_to_wasi)?
429+
};
430+
let bytes = buf.as_ref();
431+
for line in String::from_utf8_lossy(&bytes[..bytes.len().min(1024)]).lines() {
432+
if fd == 2 {
433+
error!(target: "sidevm", "{}", line);
434+
} else {
435+
info!(target: "sidevm", "{}", line);
436+
}
437+
}
438+
written += buf.len();
439+
}
440+
let nwritten_ref = nwritten.deref(&memory);
441+
let written: u32 = wasi_try_ok!(written.try_into().map_err(|_| Errno::Overflow));
442+
wasi_try_mem_ok!(nwritten_ref.write(written));
443+
Ok(Errno::Success)
364444
}
365445

366446
pub fn path_create_directory(

crates/sidevm/host/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ sidevm-host-runtime = { path = "../host-runtime", features = [
1010
] }
1111
tokio = { version = "1.17.0", features = ["full"] }
1212
log = "0.4"
13-
env_logger = "0.9.0"
13+
tracing-subscriber = "0.3"
1414
anyhow = "1.0.69"
1515
clap = { version = "4.0.32", features = ["derive"] }
1616
once_cell = "1"

crates/sidevm/host/src/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ pub struct Args {
1717
workers: usize,
1818
/// The WASM program to run
1919
program: Option<String>,
20+
/// Max memory pages
21+
#[arg(long, default_value_t = 256)]
22+
max_memory_pages: u32,
2023
}
2124

2225
fn simple_cache() -> DynCacheOps {
@@ -56,7 +59,7 @@ fn simple_cache() -> DynCacheOps {
5659

5760
#[tokio::main]
5861
async fn main() -> anyhow::Result<()> {
59-
env_logger::init();
62+
tracing_subscriber::fmt::init();
6063
if std::env::var("ROCKET_PORT").is_err() {
6164
std::env::set_var("ROCKET_PORT", "8003");
6265
}

crates/sidevm/host/src/web_api.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl App {
6363
.spawner
6464
.start(
6565
&wasm_bytes,
66-
1024,
66+
inner.args.max_memory_pages,
6767
vmid,
6868
inner.args.gas_per_breath,
6969
crate::simple_cache(),

0 commit comments

Comments
 (0)