@@ -2,8 +2,10 @@ use super::{Env as WasiEnv, Result};
2
2
use libc:: { clock_getres, clock_gettime, timespec, CLOCK_MONOTONIC , CLOCK_REALTIME } ;
3
3
use sidevm_env:: { OcallError , OcallFuncs } ;
4
4
use thiserror:: Error ;
5
+ use tracing:: { error, info} ;
5
6
use wasmer:: {
6
- namespace, AsStoreMut , Exports , Function , FunctionEnv , FunctionEnvMut , Memory32 , WasmPtr ,
7
+ namespace, AsStoreMut , Exports , Function , FunctionEnv , FunctionEnvMut , Memory32 ,
8
+ MemoryAccessError , WasmPtr ,
7
9
} ;
8
10
use wasmer_wasix_types:: {
9
11
types:: * ,
@@ -34,6 +36,43 @@ macro_rules! wasi_try {
34
36
} } ;
35
37
}
36
38
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
+
37
76
pub ( crate ) fn wasi_imports ( store : & mut impl AsStoreMut , env : & FunctionEnv < WasiEnv > ) -> Exports {
38
77
namespace ! {
39
78
"args_get" => Function :: new_typed_with_env( store, env, args_get) ,
@@ -353,14 +392,55 @@ pub fn fd_tell(
353
392
Errno :: Nosys
354
393
}
355
394
395
+ #[ tracing:: instrument( skip_all, fields( fd = fd) ) ]
356
396
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 )
364
444
}
365
445
366
446
pub fn path_create_directory (
0 commit comments