From f3fc438ffa17d3c76e1479685a562658efca9513 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Thu, 21 Jul 2022 14:45:06 +0300 Subject: [PATCH 01/65] c-api: add functions to overwrite stdin and to write to it Fixes #2334 --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 59 ++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 4501b83f44f..c74a7d60f07 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -158,6 +158,12 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { config.inherit_stdin = true; } +#[no_mangle] +pub extern "C" fn wasi_config_overwrite_stdin(config: &mut wasi_config_t) { + let piped_stdin = Box::new(Pipe::new()); + config.state_builder.stdin(piped_stdin); +} + #[allow(non_camel_case_types)] pub struct wasi_env_t { /// cbindgen:ignore @@ -250,6 +256,23 @@ pub unsafe extern "C" fn wasi_env_read_stderr( } } +#[no_mangle] +pub unsafe extern "C" fn wasi_env_write_stdin( + env: &mut wasi_env_t, + buffer: *const u8, + buffer_len: usize, +) -> bool { + let mut store_mut = env.store.store_mut(); + let state = env.inner.data_mut(&mut store_mut).state(); + let mut stdin = + c_try!(state.stdin(); otherwise false).ok_or("Could not access WASI's state stdin"); + let wasi_stdin = c_try!(stdin.as_mut(); otherwise false); + let buffer = slice::from_raw_parts(buffer, buffer_len); + let msg = c_try!(std::str::from_utf8(buffer); otherwise false); + c_try!(write!(wasi_stdin, "{}", msg); otherwise false); + true +} + fn read_inner( wasi_file: &mut Box, inner_buffer: &mut [u8], @@ -503,4 +526,40 @@ mod tests { }) .success(); } + + #[test] + fn test_wasi_stdin_set() { + (assert_c! { + #include "tests/wasmer.h" + + int main() { + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + wasi_config_t* config = wasi_config_new("example_program"); + wasi_config_capture_stdout(config); + wasi_config_overwrite_stdin(config); + + wasm_byte_vec_t wat; + wasmer_byte_vec_new_from_string(&wat, "(module (import \"wasi_unstable\" \"args_get\" (func (param i32 i32) (result i32))))"); + wasm_byte_vec_t wasm; + wat2wasm(&wat, &wasm); + + wasm_module_t* module = wasm_module_new(store, &wasm); + assert(module); + + // TODO FIXME + // + // Test captured stdin + + wasm_module_delete(module); + wasm_byte_vec_delete(&wasm); + wasm_byte_vec_delete(&wat); + wasm_store_delete(store); + wasm_engine_delete(engine); + + return 0; + } + }) + .success(); + } } From b1c77a1c34d7108ffe69486e02421f9a621a30b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 25 Jul 2022 17:18:25 +0200 Subject: [PATCH 02/65] Refactor overriding stdin / stdout / stderr into wasi_console_io_override_t --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 269 ++++++++++++++++++++++++--- 1 file changed, 244 insertions(+), 25 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index c74a7d60f07..1015ef6f8cd 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -10,20 +10,218 @@ use super::{ store::{wasm_store_t, StoreRef}, }; use crate::error::update_last_error; -use std::convert::TryFrom; +use std::{io::{self, SeekFrom}, fmt, convert::TryFrom, sync::{atomic::{AtomicBool, Ordering}, MutexGuard}}; use std::ffi::CStr; +use std::convert::TryInto; +use std::sync::{Mutex, Arc}; use std::os::raw::c_char; use std::slice; use wasmer_wasi::{ - get_wasi_version, Pipe, WasiFile, WasiFunctionEnv, WasiState, WasiStateBuilder, WasiVersion, + get_wasi_version, VirtualFile, FsError, + WasiFile, WasiFunctionEnv, WasiState, + WasiStateBuilder, WasiVersion, }; +/// Function callback that takes: +/// +/// - a *mut to the environment data (passed in on creation), +/// - the length of the environment data +/// - a *const to the bytes to write +/// - the length of the bytes to write +pub type WasiConsoleIoReadCallback = unsafe extern "C" fn(*mut c_char, usize, *mut c_char, usize) -> i64; +pub type WasiConsoleIoWriteCallback = unsafe extern "C" fn(*mut c_char, usize, *const c_char, usize, bool) -> i64; +pub type WasiConsoleIoSeekCallback = unsafe extern "C" fn(*mut c_char, usize, c_char, i64) -> i64; +pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn (*mut c_char, usize) -> i64; + +/// The console override is a custom context consisting of callback pointers +/// (which are activated whenever some console I/O occurs) and a "context", which +/// can be owned or referenced from C. This struct can be used in `wasi_config_overwrite_stdin`, +/// `wasi_config_overwrite_stdout` or `wasi_config_overwrite_stderr` to redirect the output or +/// insert input into the console I/O log. +/// +/// Internally the stdout / stdin is synchronized, so the console is usable across threads +/// (only one thread can read / write / seek from the console I/O) +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct wasi_console_io_override_t { + read: WasiConsoleIoReadCallback, + write: WasiConsoleIoWriteCallback, + seek: WasiConsoleIoSeekCallback, + destructor: WasiConsoleIoEnvDestructor, + data: Option>>>, + dropped: AtomicBool, +} + +impl wasi_console_io_override_t { + fn get_data_mut(&mut self, op_id: &'static str) -> io::Result>> { + self.data + .as_mut() + .ok_or({ + io::Error::new(io::ErrorKind::Other, format!("could not lock mutex ({op_id}) on wasi_console_io_override_t: no mutex")) + })? + .lock() + .map_err(|e| { + io::Error::new(io::ErrorKind::Other, format!("could not lock mutex ({op_id}) on wasi_console_io_override_t: {e}")) + }) + } +} + +impl Drop for wasi_console_io_override_t { + fn drop(&mut self) { + + let data = match self.data.take() { + Some(s) => s, + None => { return; }, + }; + + let value = match Arc::try_unwrap(data) { + Ok(o) => o, + Err(_) => { return; }, + }; + + let mut inner_value = match value.into_inner() { + Ok(o) => o, + Err(_) => { return; }, + }; + + if self.dropped.load(Ordering::SeqCst) { + return; + } + + let error = unsafe { (self.destructor)(inner_value.as_mut_ptr(), inner_value.len()) }; + if error <= 0 { + println!("error dropping wasi_console_io_override_t: {error}"); + } + + self.dropped.store(true, Ordering::SeqCst); + } +} + +impl fmt::Debug for wasi_console_io_override_t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "wasi_console_io_override_t") + } +} + +impl io::Read for wasi_console_io_override_t { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let self_read = self.read.clone(); + let mut data = self.get_data_mut("read")?; + let result = unsafe { (self_read)(data.as_mut_ptr(), data.len(), buf.as_mut_ptr() as *mut c_char, buf.len()) }; + if result >= 0 { + Ok(result as usize) + } else { + Err(io::Error::new(io::ErrorKind::Other, format!("could not read from wasi_console_io_override_t: {result}"))) + } + } +} + +impl io::Write for wasi_console_io_override_t { + fn write(&mut self, buf: &[u8]) -> io::Result { + let self_write = self.write.clone(); + let mut data = self.get_data_mut("write")?; + let result = unsafe { (self_write)(data.as_mut_ptr(), data.len(), buf.as_ptr() as *const c_char, buf.len(), false) }; + if result >= 0 { + Ok(result.try_into().unwrap_or(0)) + } else { + Err(std::io::Error::new(std::io::ErrorKind::Other, format!("could not write {} bytes to wasi_console_io_override_t: {result}", buf.len()))) + } + } + fn flush(&mut self) -> io::Result<()> { + let self_write = self.write.clone(); + let mut data = self.get_data_mut("flush")?; + let bytes_to_write = &[]; + let result: i64 = unsafe { (self_write)(data.as_mut_ptr(), data.len(), bytes_to_write.as_ptr(), 0, true) }; + if result >= 0 { + Ok(()) + } else { + Err(std::io::Error::new(std::io::ErrorKind::Other, format!("could not flush wasi_console_io_override_t: {result}"))) + } + } +} + +impl io::Seek for wasi_console_io_override_t { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + let self_seek = self.seek.clone(); + let mut data = self.get_data_mut("seek")?; + let (id, pos) = match pos { + SeekFrom::Start(s) => (0, s as i64), + SeekFrom::End(s) => (1, s), + SeekFrom::Current(s) => (2, s), + }; + let result = unsafe { (self_seek)(data.as_mut_ptr(), data.len(), id, pos) }; + if result >= 0 { + Ok(result.try_into().unwrap_or(0)) + } else { + Err(std::io::Error::new(std::io::ErrorKind::Other, format!("could not seek to {pos:?} wasi_console_io_override_t: {result}"))) + } + } +} + +impl VirtualFile for wasi_console_io_override_t { + fn last_accessed(&self) -> u64 { 0 } + fn last_modified(&self) -> u64 { 0 } + fn created_time(&self) -> u64 { 0 } + fn size(&self) -> u64 { 0 } + fn set_len(&mut self, _: u64) -> Result<(), FsError> { Ok(()) } + fn unlink(&mut self) -> Result<(), FsError> { Ok(()) } +} + +/// Creates a new callback object that is being +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_new( + read: WasiConsoleIoReadCallback, + write: WasiConsoleIoWriteCallback, + seek: WasiConsoleIoSeekCallback, + destructor: WasiConsoleIoEnvDestructor, + env_data: *mut c_char, + env_data_len: usize, + transfer_ownership: bool, +) -> *mut wasi_console_io_override_t { + + let data_vec = if transfer_ownership { + std::slice::from_raw_parts(env_data, env_data_len).to_vec() + } else { + Vec::from_raw_parts(env_data, env_data_len, env_data_len) + }; + + Box::leak(Box::new(wasi_console_io_override_t { + read, + write, + seek, + destructor, + data: Some(Arc::new(Mutex::new(data_vec))), + dropped: AtomicBool::new(false), + })) +} + +/// Creates a `wasi_console_io_override_t` callback object that does nothing +/// and redirects stdout / stderr to /dev/null +#[no_mangle] +pub unsafe extern "C" fn wasi_console_override_new_null() -> *mut wasi_console_io_override_t { + let mut data = Vec::new(); + wasi_console_io_override_new( + wasi_console_io_override_read, + wasi_console_io_override_write, + wasi_console_io_override_seek, + wasi_console_io_override_delete, + data.as_mut_ptr(), + data.len(), + true + ) +} + +extern "C" fn wasi_console_io_override_read(_: *mut c_char, _:usize, _:*mut c_char, _: usize) -> i64 { 0 } +extern "C" fn wasi_console_io_override_write(_: *mut c_char, _: usize, _: *const c_char, _: usize, _: bool) -> i64 { 0 } +extern "C" fn wasi_console_io_override_seek(_: *mut c_char, _: usize, _: c_char, _: i64) -> i64 { 0 } +extern "C" fn wasi_console_io_override_delete(_: *mut c_char, _: usize) -> i64 { 0 } + #[derive(Debug)] #[allow(non_camel_case_types)] pub struct wasi_config_t { - inherit_stdout: bool, - inherit_stderr: bool, - inherit_stdin: bool, + inherit_stdout: Option>, + inherit_stderr: Option>, + inherit_stdin: Option>, state_builder: WasiStateBuilder, } @@ -37,9 +235,9 @@ pub unsafe extern "C" fn wasi_config_new( let prog_name = c_try!(name_c_str.to_str()); Some(Box::new(wasi_config_t { - inherit_stdout: true, - inherit_stderr: true, - inherit_stdin: true, + inherit_stdout: None, + inherit_stderr: None, + inherit_stdin: None, state_builder: WasiState::new(prog_name), })) } @@ -130,38 +328,56 @@ pub unsafe extern "C" fn wasi_config_mapdir( #[no_mangle] pub extern "C" fn wasi_config_capture_stdout(config: &mut wasi_config_t) { - config.inherit_stdout = false; + config.inherit_stdout = Some(unsafe { Box::from_raw(wasi_console_override_new_null()) }); } #[no_mangle] pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { - config.inherit_stdout = true; + config.inherit_stdout = None; } #[no_mangle] pub extern "C" fn wasi_config_capture_stderr(config: &mut wasi_config_t) { - config.inherit_stderr = false; + config.inherit_stderr = Some(unsafe { Box::from_raw(wasi_console_override_new_null()) }); } #[no_mangle] pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { - config.inherit_stderr = true; + config.inherit_stderr = None; } -//#[no_mangle] -//pub extern "C" fn wasi_config_capture_stdin(config: &mut wasi_config_t) { -// config.inherit_stdin = false; -//} +#[no_mangle] +pub extern "C" fn wasi_config_capture_stdin(config: &mut wasi_config_t) { + config.inherit_stdin = Some(unsafe { Box::from_raw(wasi_console_override_new_null()) }); +} #[no_mangle] pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { - config.inherit_stdin = true; + config.inherit_stdin = None; +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_config_overwrite_stdin( + config: &mut wasi_config_t, + stdin: *mut wasi_console_io_override_t +) { + config.state_builder.stdin(Box::from_raw(stdin)); +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_config_overwrite_stdout( + config: &mut wasi_config_t, + stdout: *mut wasi_console_io_override_t +) { + config.state_builder.stdout(Box::from_raw(stdout)); } #[no_mangle] -pub extern "C" fn wasi_config_overwrite_stdin(config: &mut wasi_config_t) { - let piped_stdin = Box::new(Pipe::new()); - config.state_builder.stdin(piped_stdin); +pub unsafe extern "C" fn wasi_config_overwrite_stderr( + config: &mut wasi_config_t, + stderr: *mut wasi_console_io_override_t +) { + config.state_builder.stderr(Box::from_raw(stderr)); } #[allow(non_camel_case_types)] @@ -181,15 +397,18 @@ pub unsafe extern "C" fn wasi_env_new( ) -> Option> { let store = &mut store?.inner; let mut store_mut = store.store_mut(); - if !config.inherit_stdout { - config.state_builder.stdout(Box::new(Pipe::new())); + + if let Some(stdout) = config.inherit_stdout { + config.state_builder.stdout(stdout); } - if !config.inherit_stderr { - config.state_builder.stderr(Box::new(Pipe::new())); + if let Some(stderr) = config.inherit_stderr { + config.state_builder.stderr(stderr); } - // TODO: impl capturer for stdin + if let Some(stdin) = config.inherit_stdin { + config.state_builder.stdin(stdin); + } let wasi_state = c_try!(config.state_builder.finalize(&mut store_mut)); From 759b2f619869197b321d72b3aabc317a42f0586c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 26 Jul 2022 10:23:22 +0200 Subject: [PATCH 03/65] Add (non-working) unit test --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 105 ++++++++++++++++++ lib/c-api/tests/wasm-c-api/example/stdio.wasm | Bin 0 -> 66338 bytes 2 files changed, 105 insertions(+) create mode 100755 lib/c-api/tests/wasm-c-api/example/stdio.wasm diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 1015ef6f8cd..1ddeb3784fd 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -43,6 +43,7 @@ pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn (*mut c_char, usize) /// (only one thread can read / write / seek from the console I/O) #[allow(non_camel_case_types)] #[repr(C)] +#[derive(Clone)] pub struct wasi_console_io_override_t { read: WasiConsoleIoReadCallback, write: WasiConsoleIoWriteCallback, @@ -195,6 +196,78 @@ pub unsafe extern "C" fn wasi_console_io_override_new( })) } +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_delete( + ptr: *mut wasi_console_io_override_t +) { + Box::from_raw(ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_write_bytes( + ptr: *mut wasi_console_io_override_t, + buf: *const c_char, + len: usize, +) -> i32 { + +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_read_bytes( + ptr: *mut wasi_console_io_override_t, + buf: *mut c_char, + len: usize, +) -> i32 { + +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_write_str( + ptr: *mut wasi_console_io_override_t, + buf: *const c_char, +) -> i32 { + +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_read_str( + ptr: *mut wasi_console_io_override_t, + buf: *mut c_char, +) -> i32 { + +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_seek( + ptr: *mut wasi_console_io_override_t, + // 0 = from start + // 1 = from end + // 2 = from current position + seek_dir: c_char, + seek: i64, +) -> i64 { + + let seek_pos = match seek_dir { + 0 => SeekFrom::Start(seek as usize), + 1 => SeekFrom::End(seek), + 2 => SeekFrom::Current(seek), + }; + + let ptr = unsafe { &mut *ptr }; + + ptr + .seek(seek_pos) + .map(|p| p.try_into().ok()) + .unwrap_or(-1) +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_clone( + ptr: *const wasi_console_io_override_t +) -> *mut wasi_console_io_override_t { + unsafe { &*ptr }.clone() +} + /// Creates a `wasi_console_io_override_t` callback object that does nothing /// and redirects stdout / stderr to /dev/null #[no_mangle] @@ -662,10 +735,40 @@ mod tests { wasm_byte_vec_t wasm; wat2wasm(&wat, &wasm); + wasi_console_io_override_t* override_stdin = wasi_console_io_override_new( + + ); + wasi_console_io_override_t* override_stdout = wasi_console_io_override_new( + + ); + wasi_console_io_override_t* override_stdin = wasi_console_io_override_new( + + ); + + // Cloning the `wasi_console_io_override_t` does not deep-clone the + // internal stream, since that is locked behind an Arc>. + wasi_console_io_override_t* stdin_sender = wasi_console_io_override_clone(&override_stdin); + wasi_console_io_override_t* stdout_receiver = wasi_console_io_override_clone(&override_stdout); + wasi_console_io_override_t* stderr_receiver = wasi_console_io_override_clone(&override_stderr); + wasm_module_t* module = wasm_module_new(store, &wasm); assert(module); assert(wasi_get_wasi_version(module) == SNAPSHOT0); + + // The program should wait for a stdin, then print "stdout: $1" to stdout + // and "stderr: $1" to stderr and exit. + wasi_console_io_override_write_str(stdin_sender, "hello\0"); + + assert(wasi_console_io_override_read_str(stdout_receiver), "stdout: hello\0"); + assert(wasi_console_io_override_read_str(stdout_receiver), "\0"); + + assert(wasi_console_io_override_read_str(stderr_receiver), "stderr: hello\0"); + assert(wasi_console_io_override_read_str(stderr_receiver), "\0"); + + wasi_console_io_override_delete(stdin_sender); + wasi_console_io_override_delete(stdout_receiver); + wasi_console_io_override_delete(stderr_receiver); wasm_module_delete(module); wasm_byte_vec_delete(&wasm); @@ -751,6 +854,8 @@ mod tests { (assert_c! { #include "tests/wasmer.h" + struct MyCustomStdin { } + int main() { wasm_engine_t* engine = wasm_engine_new(); wasm_store_t* store = wasm_store_new(engine); diff --git a/lib/c-api/tests/wasm-c-api/example/stdio.wasm b/lib/c-api/tests/wasm-c-api/example/stdio.wasm new file mode 100755 index 0000000000000000000000000000000000000000..9ed5b3d4709f9f57860742a50a42601d84f030df GIT binary patch literal 66338 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 R=s)~@^QN-Ee>wdA{{V3ZoEiWC literal 0 HcmV?d00001 From 8e5ff7ddf6c98c269e30639d823d7f522c00076b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 26 Jul 2022 10:25:37 +0200 Subject: [PATCH 04/65] Remove wasi_env_write_stdin --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 1ddeb3784fd..57cd2a2bb97 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -548,23 +548,6 @@ pub unsafe extern "C" fn wasi_env_read_stderr( } } -#[no_mangle] -pub unsafe extern "C" fn wasi_env_write_stdin( - env: &mut wasi_env_t, - buffer: *const u8, - buffer_len: usize, -) -> bool { - let mut store_mut = env.store.store_mut(); - let state = env.inner.data_mut(&mut store_mut).state(); - let mut stdin = - c_try!(state.stdin(); otherwise false).ok_or("Could not access WASI's state stdin"); - let wasi_stdin = c_try!(stdin.as_mut(); otherwise false); - let buffer = slice::from_raw_parts(buffer, buffer_len); - let msg = c_try!(std::str::from_utf8(buffer); otherwise false); - c_try!(write!(wasi_stdin, "{}", msg); otherwise false); - true -} - fn read_inner( wasi_file: &mut Box, inner_buffer: &mut [u8], From dccaa3f72a2da9d06c7a926fd4e02f466d4a252b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 26 Jul 2022 12:13:22 +0200 Subject: [PATCH 05/65] Fix C API --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 132 ++++++++++++++++++++------- 1 file changed, 101 insertions(+), 31 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 57cd2a2bb97..a129d65fa97 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -10,7 +10,7 @@ use super::{ store::{wasm_store_t, StoreRef}, }; use crate::error::update_last_error; -use std::{io::{self, SeekFrom}, fmt, convert::TryFrom, sync::{atomic::{AtomicBool, Ordering}, MutexGuard}}; +use std::{io::{self, SeekFrom}, fmt, convert::TryFrom, sync::MutexGuard}; use std::ffi::CStr; use std::convert::TryInto; use std::sync::{Mutex, Arc}; @@ -50,7 +50,7 @@ pub struct wasi_console_io_override_t { seek: WasiConsoleIoSeekCallback, destructor: WasiConsoleIoEnvDestructor, data: Option>>>, - dropped: AtomicBool, + dropped: bool, } impl wasi_console_io_override_t { @@ -85,7 +85,7 @@ impl Drop for wasi_console_io_override_t { Err(_) => { return; }, }; - if self.dropped.load(Ordering::SeqCst) { + if self.dropped { return; } @@ -94,7 +94,7 @@ impl Drop for wasi_console_io_override_t { println!("error dropping wasi_console_io_override_t: {error}"); } - self.dropped.store(true, Ordering::SeqCst); + self.dropped = true; } } @@ -192,15 +192,16 @@ pub unsafe extern "C" fn wasi_console_io_override_new( seek, destructor, data: Some(Arc::new(Mutex::new(data_vec))), - dropped: AtomicBool::new(false), + dropped: false, })) } #[no_mangle] pub unsafe extern "C" fn wasi_console_io_override_delete( ptr: *mut wasi_console_io_override_t -) { - Box::from_raw(ptr) +) -> bool { + let _ = Box::from_raw(ptr); + true } #[no_mangle] @@ -208,33 +209,99 @@ pub unsafe extern "C" fn wasi_console_io_override_write_bytes( ptr: *mut wasi_console_io_override_t, buf: *const c_char, len: usize, -) -> i32 { - +) -> i64 { + use std::io::Write; + let buf = buf as *const u8; + let ptr = &mut *ptr; + match ptr.write(std::slice::from_raw_parts(buf, len)) { + Ok(o) => o as i64, + Err(_) => -1, + } } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_read_bytes( +pub unsafe extern "C" fn wasi_console_io_override_write_str( ptr: *mut wasi_console_io_override_t, - buf: *mut c_char, - len: usize, -) -> i32 { + buf: *const c_char, +) -> i64 { + use std::io::Write; + let c_str = std::ffi::CStr::from_ptr(buf); + let as_bytes_with_nul = c_str.to_bytes(); + let ptr = &mut *ptr; + match ptr.write(as_bytes_with_nul) { + Ok(o) => o as i64, + Err(_) => -1, + } +} +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_flush( + ptr: *mut wasi_console_io_override_t +) -> i64 { + use std::io::Write; + let ptr = &mut *ptr; + match ptr.flush() { + Ok(_) => 0, + Err(_) => -1, + } } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_write_str( +pub unsafe extern "C" fn wasi_console_io_override_read_bytes( ptr: *mut wasi_console_io_override_t, - buf: *const c_char, -) -> i32 { + buf: *mut c_char, + read: usize, +) -> i64 { + use std::io::Read; + let ptr = &mut *ptr; + let buf = buf as *mut u8; + let slice = std::slice::from_raw_parts_mut(buf, read); + match ptr.read(slice) { + Ok(o) => o as i64, + Err(_) => -1, + } +} +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_delete_str( + buf: *mut c_char, +) { + use std::ffi::CString; + let _ = CString::from_raw(buf); } #[no_mangle] pub unsafe extern "C" fn wasi_console_io_override_read_str( ptr: *mut wasi_console_io_override_t, - buf: *mut c_char, -) -> i32 { + buf: *mut *mut c_char, +) -> i64 { + use std::ffi::CString; + use std::io::Read; + + const BLOCK_SIZE: usize = 1024; + + let mut target = Vec::new(); + let ptr = &mut *ptr; + + loop { + let mut v = vec![0;BLOCK_SIZE]; + // read n bytes, maximum of 1024 + match ptr.read(&mut v) { + Ok(0) => { break; }, + Ok(n) => { target.extend_from_slice(&v[..n]); } + Err(_) => { return -1; } + } + } + + target.push(0); + let len = target.len(); + let c_string = match CString::from_vec_with_nul(target) { + Ok(o) => o, + Err(_) => { return -1; }, + }; + *buf = CString::into_raw(c_string); + len as i64 } #[no_mangle] @@ -247,17 +314,20 @@ pub unsafe extern "C" fn wasi_console_io_override_seek( seek: i64, ) -> i64 { + use std::io::Seek; + let seek_pos = match seek_dir { - 0 => SeekFrom::Start(seek as usize), + 0 => SeekFrom::Start(seek as u64), 1 => SeekFrom::End(seek), 2 => SeekFrom::Current(seek), + _ => { return -1; }, }; - let ptr = unsafe { &mut *ptr }; + let ptr = &mut *ptr; ptr - .seek(seek_pos) - .map(|p| p.try_into().ok()) + .seek(seek_pos).ok() + .and_then(|p| p.try_into().ok()) .unwrap_or(-1) } @@ -265,7 +335,7 @@ pub unsafe extern "C" fn wasi_console_io_override_seek( pub unsafe extern "C" fn wasi_console_io_override_clone( ptr: *const wasi_console_io_override_t ) -> *mut wasi_console_io_override_t { - unsafe { &*ptr }.clone() + Box::leak(Box::new((&*ptr).clone())) } /// Creates a `wasi_console_io_override_t` callback object that does nothing @@ -274,20 +344,20 @@ pub unsafe extern "C" fn wasi_console_io_override_clone( pub unsafe extern "C" fn wasi_console_override_new_null() -> *mut wasi_console_io_override_t { let mut data = Vec::new(); wasi_console_io_override_new( - wasi_console_io_override_read, - wasi_console_io_override_write, - wasi_console_io_override_seek, - wasi_console_io_override_delete, + wasi_console_io_override_read_default, + wasi_console_io_override_write_default, + wasi_console_io_override_seek_default, + wasi_console_io_override_delete_default, data.as_mut_ptr(), data.len(), true ) } -extern "C" fn wasi_console_io_override_read(_: *mut c_char, _:usize, _:*mut c_char, _: usize) -> i64 { 0 } -extern "C" fn wasi_console_io_override_write(_: *mut c_char, _: usize, _: *const c_char, _: usize, _: bool) -> i64 { 0 } -extern "C" fn wasi_console_io_override_seek(_: *mut c_char, _: usize, _: c_char, _: i64) -> i64 { 0 } -extern "C" fn wasi_console_io_override_delete(_: *mut c_char, _: usize) -> i64 { 0 } +extern "C" fn wasi_console_io_override_read_default(_: *mut c_char, _:usize, _:*mut c_char, _: usize) -> i64 { 0 } +extern "C" fn wasi_console_io_override_write_default(_: *mut c_char, _: usize, _: *const c_char, _: usize, _: bool) -> i64 { 0 } +extern "C" fn wasi_console_io_override_seek_default(_: *mut c_char, _: usize, _: c_char, _: i64) -> i64 { 0 } +extern "C" fn wasi_console_io_override_delete_default(_: *mut c_char, _: usize) -> i64 { 0 } #[derive(Debug)] #[allow(non_camel_case_types)] From d0ccb344e324c1fab6cb8e36d6d8302b1e423fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 26 Jul 2022 15:24:36 +0200 Subject: [PATCH 06/65] Make capi unit test functional, finalize C API --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 588 +++++++++++++++++++-------- 1 file changed, 424 insertions(+), 164 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index a129d65fa97..af7ddc7f5ad 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -10,36 +10,43 @@ use super::{ store::{wasm_store_t, StoreRef}, }; use crate::error::update_last_error; -use std::{io::{self, SeekFrom}, fmt, convert::TryFrom, sync::MutexGuard}; -use std::ffi::CStr; use std::convert::TryInto; -use std::sync::{Mutex, Arc}; +use std::ffi::CStr; use std::os::raw::c_char; use std::slice; +use std::sync::{Arc, Mutex}; +use std::{ + convert::TryFrom, + fmt, + io::{self, SeekFrom}, + sync::MutexGuard, +}; use wasmer_wasi::{ - get_wasi_version, VirtualFile, FsError, - WasiFile, WasiFunctionEnv, WasiState, - WasiStateBuilder, WasiVersion, + get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiState, WasiStateBuilder, + WasiVersion, }; /// Function callback that takes: -/// -/// - a *mut to the environment data (passed in on creation), +/// +/// - a *mut to the environment data (passed in on creation), /// - the length of the environment data /// - a *const to the bytes to write -/// - the length of the bytes to write -pub type WasiConsoleIoReadCallback = unsafe extern "C" fn(*mut c_char, usize, *mut c_char, usize) -> i64; -pub type WasiConsoleIoWriteCallback = unsafe extern "C" fn(*mut c_char, usize, *const c_char, usize, bool) -> i64; -pub type WasiConsoleIoSeekCallback = unsafe extern "C" fn(*mut c_char, usize, c_char, i64) -> i64; -pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn (*mut c_char, usize) -> i64; - -/// The console override is a custom context consisting of callback pointers +/// - the length of the bytes to write +pub type WasiConsoleIoReadCallback = + unsafe extern "C" fn(*mut c_char, usize, usize, *mut c_char, usize) -> i64; +pub type WasiConsoleIoWriteCallback = + unsafe extern "C" fn(*mut c_char, usize, usize, *const c_char, usize, bool) -> i64; +pub type WasiConsoleIoSeekCallback = + unsafe extern "C" fn(*mut c_char, usize, usize, c_char, i64) -> i64; +pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*mut c_char, usize, usize) -> i64; + +/// The console override is a custom context consisting of callback pointers /// (which are activated whenever some console I/O occurs) and a "context", which -/// can be owned or referenced from C. This struct can be used in `wasi_config_overwrite_stdin`, +/// can be owned or referenced from C. This struct can be used in `wasi_config_overwrite_stdin`, /// `wasi_config_overwrite_stdout` or `wasi_config_overwrite_stderr` to redirect the output or /// insert input into the console I/O log. -/// -/// Internally the stdout / stdin is synchronized, so the console is usable across threads +/// +/// Internally the stdout / stdin is synchronized, so the console is usable across threads /// (only one thread can read / write / seek from the console I/O) #[allow(non_camel_case_types)] #[repr(C)] @@ -49,47 +56,63 @@ pub struct wasi_console_io_override_t { write: WasiConsoleIoWriteCallback, seek: WasiConsoleIoSeekCallback, destructor: WasiConsoleIoEnvDestructor, - data: Option>>>, + data: Option>>>>, + align: usize, dropped: bool, } impl wasi_console_io_override_t { fn get_data_mut(&mut self, op_id: &'static str) -> io::Result>> { self.data - .as_mut() - .ok_or({ - io::Error::new(io::ErrorKind::Other, format!("could not lock mutex ({op_id}) on wasi_console_io_override_t: no mutex")) - })? - .lock() - .map_err(|e| { - io::Error::new(io::ErrorKind::Other, format!("could not lock mutex ({op_id}) on wasi_console_io_override_t: {e}")) - }) + .as_mut() + .ok_or({ + io::Error::new( + io::ErrorKind::Other, + format!( + "could not lock mutex ({op_id}) on wasi_console_io_override_t: no mutex" + ), + ) + })? + .lock() + .map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!("could not lock mutex ({op_id}) on wasi_console_io_override_t: {e}"), + ) + }) } } impl Drop for wasi_console_io_override_t { fn drop(&mut self) { - + let align = self.align; let data = match self.data.take() { Some(s) => s, - None => { return; }, + None => { + return; + } }; - let value = match Arc::try_unwrap(data) { + let value = match Arc::try_unwrap(*data) { Ok(o) => o, - Err(_) => { return; }, + Err(_) => { + return; + } }; let mut inner_value = match value.into_inner() { Ok(o) => o, - Err(_) => { return; }, + Err(_) => { + return; + } }; if self.dropped { return; } - let error = unsafe { (self.destructor)(inner_value.as_mut_ptr(), inner_value.len()) }; + let error = + unsafe { (self.destructor)(inner_value.as_mut_ptr(), inner_value.len(), align) }; if error <= 0 { println!("error dropping wasi_console_io_override_t: {error}"); } @@ -107,12 +130,24 @@ impl fmt::Debug for wasi_console_io_override_t { impl io::Read for wasi_console_io_override_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { let self_read = self.read.clone(); + let self_align = self.align; let mut data = self.get_data_mut("read")?; - let result = unsafe { (self_read)(data.as_mut_ptr(), data.len(), buf.as_mut_ptr() as *mut c_char, buf.len()) }; + let result = unsafe { + (self_read)( + data.as_mut_ptr(), + data.len(), + self_align, + buf.as_mut_ptr() as *mut c_char, + buf.len(), + ) + }; if result >= 0 { Ok(result as usize) } else { - Err(io::Error::new(io::ErrorKind::Other, format!("could not read from wasi_console_io_override_t: {result}"))) + Err(io::Error::new( + io::ErrorKind::Other, + format!("could not read from wasi_console_io_override_t: {result}"), + )) } } } @@ -120,23 +155,52 @@ impl io::Read for wasi_console_io_override_t { impl io::Write for wasi_console_io_override_t { fn write(&mut self, buf: &[u8]) -> io::Result { let self_write = self.write.clone(); + let self_align = self.align; let mut data = self.get_data_mut("write")?; - let result = unsafe { (self_write)(data.as_mut_ptr(), data.len(), buf.as_ptr() as *const c_char, buf.len(), false) }; + let result = unsafe { + (self_write)( + data.as_mut_ptr(), + data.len(), + self_align, + buf.as_ptr() as *const c_char, + buf.len(), + false, + ) + }; if result >= 0 { Ok(result.try_into().unwrap_or(0)) } else { - Err(std::io::Error::new(std::io::ErrorKind::Other, format!("could not write {} bytes to wasi_console_io_override_t: {result}", buf.len()))) + Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!( + "could not write {} bytes to wasi_console_io_override_t: {result}", + buf.len() + ), + )) } } fn flush(&mut self) -> io::Result<()> { let self_write = self.write.clone(); + let self_align = self.align; let mut data = self.get_data_mut("flush")?; let bytes_to_write = &[]; - let result: i64 = unsafe { (self_write)(data.as_mut_ptr(), data.len(), bytes_to_write.as_ptr(), 0, true) }; + let result: i64 = unsafe { + (self_write)( + data.as_mut_ptr(), + data.len(), + self_align, + bytes_to_write.as_ptr(), + 0, + true, + ) + }; if result >= 0 { Ok(()) } else { - Err(std::io::Error::new(std::io::ErrorKind::Other, format!("could not flush wasi_console_io_override_t: {result}"))) + Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("could not flush wasi_console_io_override_t: {result}"), + )) } } } @@ -144,28 +208,44 @@ impl io::Write for wasi_console_io_override_t { impl io::Seek for wasi_console_io_override_t { fn seek(&mut self, pos: SeekFrom) -> io::Result { let self_seek = self.seek.clone(); + let self_align = self.align; let mut data = self.get_data_mut("seek")?; let (id, pos) = match pos { SeekFrom::Start(s) => (0, s as i64), SeekFrom::End(s) => (1, s), SeekFrom::Current(s) => (2, s), }; - let result = unsafe { (self_seek)(data.as_mut_ptr(), data.len(), id, pos) }; + let result = unsafe { (self_seek)(data.as_mut_ptr(), data.len(), self_align, id, pos) }; if result >= 0 { Ok(result.try_into().unwrap_or(0)) } else { - Err(std::io::Error::new(std::io::ErrorKind::Other, format!("could not seek to {pos:?} wasi_console_io_override_t: {result}"))) + Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("could not seek to {pos:?} wasi_console_io_override_t: {result}"), + )) } } } impl VirtualFile for wasi_console_io_override_t { - fn last_accessed(&self) -> u64 { 0 } - fn last_modified(&self) -> u64 { 0 } - fn created_time(&self) -> u64 { 0 } - fn size(&self) -> u64 { 0 } - fn set_len(&mut self, _: u64) -> Result<(), FsError> { Ok(()) } - fn unlink(&mut self) -> Result<(), FsError> { Ok(()) } + fn last_accessed(&self) -> u64 { + 0 + } + fn last_modified(&self) -> u64 { + 0 + } + fn created_time(&self) -> u64 { + 0 + } + fn size(&self) -> u64 { + 0 + } + fn set_len(&mut self, _: u64) -> Result<(), FsError> { + Ok(()) + } + fn unlink(&mut self) -> Result<(), FsError> { + Ok(()) + } } /// Creates a new callback object that is being @@ -177,9 +257,9 @@ pub unsafe extern "C" fn wasi_console_io_override_new( destructor: WasiConsoleIoEnvDestructor, env_data: *mut c_char, env_data_len: usize, + env_data_align: usize, transfer_ownership: bool, ) -> *mut wasi_console_io_override_t { - let data_vec = if transfer_ownership { std::slice::from_raw_parts(env_data, env_data_len).to_vec() } else { @@ -191,14 +271,209 @@ pub unsafe extern "C" fn wasi_console_io_override_new( write, seek, destructor, - data: Some(Arc::new(Mutex::new(data_vec))), + data: Some(Box::new(Arc::new(Mutex::new(data_vec)))), + align: env_data_align, dropped: false, })) } +/// Creates a `wasi_console_io_override_t` callback object that does nothing +/// and redirects stdout / stderr to /dev/null +#[no_mangle] +pub unsafe extern "C" fn wasi_console_override_new_null() -> *mut wasi_console_io_override_t { + let mut data = Vec::new(); + wasi_console_io_override_new( + wasi_console_io_override_read_null, + wasi_console_io_override_write_null, + wasi_console_io_override_seek_null, + wasi_console_io_override_delete_null, + data.as_mut_ptr(), + data.len(), + std::mem::align_of_val(&data), + true, + ) +} + +extern "C" fn wasi_console_io_override_read_null( + _: *mut c_char, + _: usize, + _: usize, + _: *mut c_char, + _: usize, +) -> i64 { + 0 +} +extern "C" fn wasi_console_io_override_write_null( + _: *mut c_char, + _: usize, + _: usize, + _: *const c_char, + _: usize, + _: bool, +) -> i64 { + 0 +} +extern "C" fn wasi_console_io_override_seek_null( + _: *mut c_char, + _: usize, + _: usize, + _: c_char, + _: i64, +) -> i64 { + 0 +} +extern "C" fn wasi_console_io_override_delete_null(_: *mut c_char, _: usize, _: usize) -> i64 { + 0 +} + +#[derive(Default)] +struct WasiConsoleMemoryOverride { + backed: Vec, + cursor: usize, +} + +unsafe extern "C" fn wasi_console_io_override_read_memory( + ptr: *mut c_char, /* = *WasiConsoleMemoryOverride */ + sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ + alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + byte_ptr: *mut c_char, /* &[u8] bytes to read */ + max_bytes: usize, /* max bytes to read */ +) -> i64 { + if sizeof != std::mem::size_of::() + || alignof != std::mem::align_of::() + { + return -1; + } + let ptr = ptr as *mut WasiConsoleMemoryOverride; + let ptr = &mut *ptr; + let read_slice = &ptr.backed[ptr.cursor..]; + let byte_ptr = byte_ptr as *mut u8; + let write_slice = std::slice::from_raw_parts_mut(byte_ptr, max_bytes); + let read = read_slice.len().min(write_slice.len()); + for (source, target) in read_slice.iter().zip(write_slice.iter_mut()) { + *target = *source; + } + ptr.cursor += read; + read as i64 +} + +unsafe extern "C" fn wasi_console_io_override_write_memory( + ptr: *mut c_char, /* = *WasiConsoleMemoryOverride */ + sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ + alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + byte_ptr: *const c_char, + byte_len: usize, + flush: bool, +) -> i64 { + if sizeof != std::mem::size_of::() + || alignof != std::mem::align_of::() + { + return -1; + } + + if flush { + return 0; + } + + let ptr = ptr as *mut WasiConsoleMemoryOverride; + let ptr = &mut *ptr; + let byte_ptr = byte_ptr as *const u8; + let read_slice = std::slice::from_raw_parts(byte_ptr, byte_len); + let bytes_to_extend = ptr.cursor + read_slice.len(); + if bytes_to_extend > ptr.backed.len() { + ptr.backed + .append(&mut vec![0; bytes_to_extend - ptr.backed.len()]); + } + let write_slice = &mut ptr.backed[ptr.cursor..(ptr.cursor + read_slice.len())]; + assert_eq!(write_slice.len(), read_slice.len()); + let written = read_slice.len(); + for (source, target) in read_slice.iter().zip(write_slice.iter_mut()) { + *target = *source; + } + written as i64 +} + +unsafe extern "C" fn wasi_console_io_override_seek_memory( + ptr: *mut c_char, /* = *WasiConsoleMemoryOverride */ + sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ + alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + direction: c_char, + seek_to: i64, +) -> i64 { + if sizeof != std::mem::size_of::() + || alignof != std::mem::align_of::() + { + return -1; + } + let ptr = ptr as *mut WasiConsoleMemoryOverride; + let ptr = &mut *ptr; + + if direction == 0 { + // seek from start + let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); + let diff = ptr.cursor as i64 - seek_to as i64; + ptr.cursor = seek_to; + diff + } else if direction == 1 { + // seek from end + let seek_to = ptr.backed.len() as i64 + seek_to; + let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); + let diff = ptr.cursor as i64 - seek_to as i64; + ptr.cursor = seek_to; + diff + } else if direction == 2 { + // seek from cursor + let seek_to = ptr.cursor as i64 + seek_to; + let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); + let diff = ptr.cursor as i64 - seek_to as i64; + ptr.cursor = seek_to; + diff + } else { + -1 + } +} + +unsafe extern "C" fn wasi_console_io_override_delete_memory( + ptr: *mut c_char, /* = *WasiConsoleMemoryOverride */ + sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ + alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ +) -> i64 { + if sizeof != std::mem::size_of::() + || alignof != std::mem::align_of::() + { + return -1; + } + let ptr = ptr as *mut WasiConsoleMemoryOverride; + let ptr = &*ptr; + let _: WasiConsoleMemoryOverride = std::mem::transmute_copy(&ptr); + // dropped here, destructors run here + 0 +} + +/// Creates a new `wasi_console_io_override_t` which uses a memory buffer +/// for backing stdin / stdout / stderr +#[no_mangle] +pub unsafe extern "C" fn wasi_console_io_override_new_memory() -> *mut wasi_console_io_override_t { + use std::mem::ManuallyDrop; + + let data = WasiConsoleMemoryOverride::default(); + let mut data = ManuallyDrop::new(data); + + wasi_console_io_override_new( + wasi_console_io_override_read_memory, + wasi_console_io_override_write_memory, + wasi_console_io_override_seek_memory, + wasi_console_io_override_delete_memory, + &mut data as *mut _ as *mut i8, + std::mem::size_of::(), + std::mem::align_of::(), + true, + ) +} + #[no_mangle] pub unsafe extern "C" fn wasi_console_io_override_delete( - ptr: *mut wasi_console_io_override_t + ptr: *mut wasi_console_io_override_t, ) -> bool { let _ = Box::from_raw(ptr); true @@ -236,7 +511,7 @@ pub unsafe extern "C" fn wasi_console_io_override_write_str( #[no_mangle] pub unsafe extern "C" fn wasi_console_io_override_flush( - ptr: *mut wasi_console_io_override_t + ptr: *mut wasi_console_io_override_t, ) -> i64 { use std::io::Write; let ptr = &mut *ptr; @@ -263,9 +538,7 @@ pub unsafe extern "C" fn wasi_console_io_override_read_bytes( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_delete_str( - buf: *mut c_char, -) { +pub unsafe extern "C" fn wasi_console_io_override_delete_str(buf: *mut c_char) { use std::ffi::CString; let _ = CString::from_raw(buf); } @@ -277,19 +550,25 @@ pub unsafe extern "C" fn wasi_console_io_override_read_str( ) -> i64 { use std::ffi::CString; use std::io::Read; - + const BLOCK_SIZE: usize = 1024; - + let mut target = Vec::new(); let ptr = &mut *ptr; - + loop { - let mut v = vec![0;BLOCK_SIZE]; + let mut v = vec![0; BLOCK_SIZE]; // read n bytes, maximum of 1024 match ptr.read(&mut v) { - Ok(0) => { break; }, - Ok(n) => { target.extend_from_slice(&v[..n]); } - Err(_) => { return -1; } + Ok(0) => { + break; + } + Ok(n) => { + target.extend_from_slice(&v[..n]); + } + Err(_) => { + return -1; + } } } @@ -297,7 +576,9 @@ pub unsafe extern "C" fn wasi_console_io_override_read_str( let len = target.len(); let c_string = match CString::from_vec_with_nul(target) { Ok(o) => o, - Err(_) => { return -1; }, + Err(_) => { + return -1; + } }; *buf = CString::into_raw(c_string); @@ -313,52 +594,32 @@ pub unsafe extern "C" fn wasi_console_io_override_seek( seek_dir: c_char, seek: i64, ) -> i64 { - use std::io::Seek; let seek_pos = match seek_dir { 0 => SeekFrom::Start(seek as u64), 1 => SeekFrom::End(seek), 2 => SeekFrom::Current(seek), - _ => { return -1; }, + _ => { + return -1; + } }; let ptr = &mut *ptr; - - ptr - .seek(seek_pos).ok() - .and_then(|p| p.try_into().ok()) - .unwrap_or(-1) + + ptr.seek(seek_pos) + .ok() + .and_then(|p| p.try_into().ok()) + .unwrap_or(-1) } #[no_mangle] pub unsafe extern "C" fn wasi_console_io_override_clone( - ptr: *const wasi_console_io_override_t + ptr: *const wasi_console_io_override_t, ) -> *mut wasi_console_io_override_t { Box::leak(Box::new((&*ptr).clone())) } -/// Creates a `wasi_console_io_override_t` callback object that does nothing -/// and redirects stdout / stderr to /dev/null -#[no_mangle] -pub unsafe extern "C" fn wasi_console_override_new_null() -> *mut wasi_console_io_override_t { - let mut data = Vec::new(); - wasi_console_io_override_new( - wasi_console_io_override_read_default, - wasi_console_io_override_write_default, - wasi_console_io_override_seek_default, - wasi_console_io_override_delete_default, - data.as_mut_ptr(), - data.len(), - true - ) -} - -extern "C" fn wasi_console_io_override_read_default(_: *mut c_char, _:usize, _:*mut c_char, _: usize) -> i64 { 0 } -extern "C" fn wasi_console_io_override_write_default(_: *mut c_char, _: usize, _: *const c_char, _: usize, _: bool) -> i64 { 0 } -extern "C" fn wasi_console_io_override_seek_default(_: *mut c_char, _: usize, _: c_char, _: i64) -> i64 { 0 } -extern "C" fn wasi_console_io_override_delete_default(_: *mut c_char, _: usize) -> i64 { 0 } - #[derive(Debug)] #[allow(non_camel_case_types)] pub struct wasi_config_t { @@ -501,24 +762,24 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdin( - config: &mut wasi_config_t, - stdin: *mut wasi_console_io_override_t + config: &mut wasi_config_t, + stdin: *mut wasi_console_io_override_t, ) { config.state_builder.stdin(Box::from_raw(stdin)); } #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdout( - config: &mut wasi_config_t, - stdout: *mut wasi_console_io_override_t + config: &mut wasi_config_t, + stdout: *mut wasi_console_io_override_t, ) { config.state_builder.stdout(Box::from_raw(stdout)); } #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stderr( - config: &mut wasi_config_t, - stderr: *mut wasi_console_io_override_t + config: &mut wasi_config_t, + stderr: *mut wasi_console_io_override_t, ) { config.state_builder.stderr(Box::from_raw(stderr)); } @@ -777,55 +1038,92 @@ mod tests { fn test_wasi_get_wasi_version_snapshot0() { (assert_c! { #include "tests/wasmer.h" + #include "string.h" + #include "stdio.h" int main() { wasm_engine_t* engine = wasm_engine_new(); wasm_store_t* store = wasm_store_new(engine); - wasmer_funcenv_t* env = wasmer_funcenv_new(store, 0); - - wasm_byte_vec_t wat; - wasmer_byte_vec_new_from_string(&wat, "(module (import \"wasi_unstable\" \"args_get\" (func (param i32 i32) (result i32))))"); - wasm_byte_vec_t wasm; - wat2wasm(&wat, &wasm); - - wasi_console_io_override_t* override_stdin = wasi_console_io_override_new( - - ); - wasi_console_io_override_t* override_stdout = wasi_console_io_override_new( - - ); - wasi_console_io_override_t* override_stdin = wasi_console_io_override_new( + wasi_config_t* config = wasi_config_new("example_program"); - ); + wasi_console_io_override_t* override_stdin = wasi_console_io_override_new_memory(); + wasi_console_io_override_t* override_stdout = wasi_console_io_override_new_memory(); + wasi_console_io_override_t* override_stderr = wasi_console_io_override_new_memory(); // Cloning the `wasi_console_io_override_t` does not deep-clone the // internal stream, since that is locked behind an Arc>. - wasi_console_io_override_t* stdin_sender = wasi_console_io_override_clone(&override_stdin); - wasi_console_io_override_t* stdout_receiver = wasi_console_io_override_clone(&override_stdout); - wasi_console_io_override_t* stderr_receiver = wasi_console_io_override_clone(&override_stderr); - - wasm_module_t* module = wasm_module_new(store, &wasm); + wasi_console_io_override_t* stdin_sender = wasi_console_io_override_clone(override_stdin); + wasi_console_io_override_t* stdout_receiver = wasi_console_io_override_clone(override_stdout); + wasi_console_io_override_t* stderr_receiver = wasi_console_io_override_clone(override_stderr); + + // The override_stdin ownership is moved to the config + wasi_config_overwrite_stdin(config, override_stdin); + wasi_config_overwrite_stdout(config, override_stdout); + wasi_config_overwrite_stderr(config, override_stderr); + + // The env now has ownership of the config (using the custom stdout / stdin channels) + wasmer_funcenv_t* env = wasmer_funcenv_new(store, config); + + FILE *fileptr; + char *buffer; + long filelen; + + fileptr = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); + if (!fileptr) { + assert(false); // file not found + } + fseek(fileptr, 0, SEEK_END); + filelen = ftell(fileptr); + rewind(fileptr); + + buffer = (char *)malloc(filelen * sizeof(char)); + if (!fread(buffer, filelen, 1, fileptr)) { + assert(false); + } + fclose(fileptr); + + // convert to wasm_byte_vec_t + wasm_byte_vec_t* wasm = 0; + wasm_byte_vec_new(wasm, filelen, buffer); + + wasm_module_t* module = wasm_module_new(store, wasm); assert(module); assert(wasi_get_wasi_version(module) == SNAPSHOT0); - + // The program should wait for a stdin, then print "stdout: $1" to stdout // and "stderr: $1" to stderr and exit. - wasi_console_io_override_write_str(stdin_sender, "hello\0"); - - assert(wasi_console_io_override_read_str(stdout_receiver), "stdout: hello\0"); - assert(wasi_console_io_override_read_str(stdout_receiver), "\0"); + wasi_console_io_override_write_str(stdin_sender, "hello"); + + char* out; + + wasi_console_io_override_read_str(stdout_receiver, &out); + printf("stdout 1: \"%s\"\n", out); + assert(strcmp(out, "stdout: hello") == 0); + wasi_console_io_override_delete_str(out); + + wasi_console_io_override_read_str(stdout_receiver, &out); + printf("stdout 2: \"%s\"\n", out); + assert(strcmp(out, "")); + wasi_console_io_override_delete_str(out); - assert(wasi_console_io_override_read_str(stderr_receiver), "stderr: hello\0"); - assert(wasi_console_io_override_read_str(stderr_receiver), "\0"); + wasi_console_io_override_read_str(stderr_receiver, &out); + printf("stdout 3: \"%s\"\n", out); + assert(strcmp(out, "stderr: hello")); + wasi_console_io_override_delete_str(out); + + wasi_console_io_override_read_str(stderr_receiver, &out); + printf("stdout 4: \"%s\"\n", out); + assert(strcmp(out, "")); + wasi_console_io_override_delete_str(out); wasi_console_io_override_delete(stdin_sender); wasi_console_io_override_delete(stdout_receiver); wasi_console_io_override_delete(stderr_receiver); + free(buffer); wasm_module_delete(module); - wasm_byte_vec_delete(&wasm); - wasm_byte_vec_delete(&wat); + wasm_byte_vec_delete(wasm); wasmer_funcenv_delete(env); wasm_store_delete(store); wasm_engine_delete(engine); @@ -901,42 +1199,4 @@ mod tests { }) .success(); } - - #[test] - fn test_wasi_stdin_set() { - (assert_c! { - #include "tests/wasmer.h" - - struct MyCustomStdin { } - - int main() { - wasm_engine_t* engine = wasm_engine_new(); - wasm_store_t* store = wasm_store_new(engine); - wasi_config_t* config = wasi_config_new("example_program"); - wasi_config_capture_stdout(config); - wasi_config_overwrite_stdin(config); - - wasm_byte_vec_t wat; - wasmer_byte_vec_new_from_string(&wat, "(module (import \"wasi_unstable\" \"args_get\" (func (param i32 i32) (result i32))))"); - wasm_byte_vec_t wasm; - wat2wasm(&wat, &wasm); - - wasm_module_t* module = wasm_module_new(store, &wasm); - assert(module); - - // TODO FIXME - // - // Test captured stdin - - wasm_module_delete(module); - wasm_byte_vec_delete(&wasm); - wasm_byte_vec_delete(&wat); - wasm_store_delete(store); - wasm_engine_delete(engine); - - return 0; - } - }) - .success(); - } } From 660f8669b91ecc639f9d57133eba48974b5936d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 29 Jul 2022 15:32:53 +0200 Subject: [PATCH 07/65] Fix double free() in deallocation of WasiConsoleMemoryOverride --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 98 +++++++++++++++------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index af7ddc7f5ad..4e1c0b6be35 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -17,6 +17,7 @@ use std::slice; use std::sync::{Arc, Mutex}; use std::{ convert::TryFrom, + ffi::c_void, fmt, io::{self, SeekFrom}, sync::MutexGuard, @@ -33,12 +34,12 @@ use wasmer_wasi::{ /// - a *const to the bytes to write /// - the length of the bytes to write pub type WasiConsoleIoReadCallback = - unsafe extern "C" fn(*mut c_char, usize, usize, *mut c_char, usize) -> i64; + unsafe extern "C" fn(*const c_void, usize, usize, *mut c_char, usize) -> i64; pub type WasiConsoleIoWriteCallback = - unsafe extern "C" fn(*mut c_char, usize, usize, *const c_char, usize, bool) -> i64; + unsafe extern "C" fn(*const c_void, usize, usize, *const c_char, usize, bool) -> i64; pub type WasiConsoleIoSeekCallback = - unsafe extern "C" fn(*mut c_char, usize, usize, c_char, i64) -> i64; -pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*mut c_char, usize, usize) -> i64; + unsafe extern "C" fn(*const c_void, usize, usize, c_char, i64) -> i64; +pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void, usize, usize) -> i64; /// The console override is a custom context consisting of callback pointers /// (which are activated whenever some console I/O occurs) and a "context", which @@ -111,9 +112,14 @@ impl Drop for wasi_console_io_override_t { return; } - let error = - unsafe { (self.destructor)(inner_value.as_mut_ptr(), inner_value.len(), align) }; - if error <= 0 { + let error = unsafe { + (self.destructor)( + inner_value.as_mut_ptr() as *const c_void, + inner_value.len(), + align, + ) + }; + if error < 0 { println!("error dropping wasi_console_io_override_t: {error}"); } @@ -134,7 +140,7 @@ impl io::Read for wasi_console_io_override_t { let mut data = self.get_data_mut("read")?; let result = unsafe { (self_read)( - data.as_mut_ptr(), + data.as_mut_ptr() as *const c_void, data.len(), self_align, buf.as_mut_ptr() as *mut c_char, @@ -159,7 +165,7 @@ impl io::Write for wasi_console_io_override_t { let mut data = self.get_data_mut("write")?; let result = unsafe { (self_write)( - data.as_mut_ptr(), + data.as_mut_ptr() as *const c_void, data.len(), self_align, buf.as_ptr() as *const c_char, @@ -186,7 +192,7 @@ impl io::Write for wasi_console_io_override_t { let bytes_to_write = &[]; let result: i64 = unsafe { (self_write)( - data.as_mut_ptr(), + data.as_mut_ptr() as *const c_void, data.len(), self_align, bytes_to_write.as_ptr(), @@ -215,7 +221,15 @@ impl io::Seek for wasi_console_io_override_t { SeekFrom::End(s) => (1, s), SeekFrom::Current(s) => (2, s), }; - let result = unsafe { (self_seek)(data.as_mut_ptr(), data.len(), self_align, id, pos) }; + let result = unsafe { + (self_seek)( + data.as_mut_ptr() as *const c_void, + data.len(), + self_align, + id, + pos, + ) + }; if result >= 0 { Ok(result.try_into().unwrap_or(0)) } else { @@ -255,16 +269,11 @@ pub unsafe extern "C" fn wasi_console_io_override_new( write: WasiConsoleIoWriteCallback, seek: WasiConsoleIoSeekCallback, destructor: WasiConsoleIoEnvDestructor, - env_data: *mut c_char, + env_data: *const c_char, env_data_len: usize, env_data_align: usize, - transfer_ownership: bool, ) -> *mut wasi_console_io_override_t { - let data_vec = if transfer_ownership { - std::slice::from_raw_parts(env_data, env_data_len).to_vec() - } else { - Vec::from_raw_parts(env_data, env_data_len, env_data_len) - }; + let data_vec: Vec = std::slice::from_raw_parts(env_data, env_data_len).to_vec(); Box::leak(Box::new(wasi_console_io_override_t { read, @@ -290,12 +299,11 @@ pub unsafe extern "C" fn wasi_console_override_new_null() -> *mut wasi_console_i data.as_mut_ptr(), data.len(), std::mem::align_of_val(&data), - true, ) } extern "C" fn wasi_console_io_override_read_null( - _: *mut c_char, + _: *const c_void, _: usize, _: usize, _: *mut c_char, @@ -304,7 +312,7 @@ extern "C" fn wasi_console_io_override_read_null( 0 } extern "C" fn wasi_console_io_override_write_null( - _: *mut c_char, + _: *const c_void, _: usize, _: usize, _: *const c_char, @@ -314,7 +322,7 @@ extern "C" fn wasi_console_io_override_write_null( 0 } extern "C" fn wasi_console_io_override_seek_null( - _: *mut c_char, + _: *const c_void, _: usize, _: usize, _: c_char, @@ -322,7 +330,8 @@ extern "C" fn wasi_console_io_override_seek_null( ) -> i64 { 0 } -extern "C" fn wasi_console_io_override_delete_null(_: *mut c_char, _: usize, _: usize) -> i64 { + +extern "C" fn wasi_console_io_override_delete_null(_: *const c_void, _: usize, _: usize) -> i64 { 0 } @@ -333,7 +342,7 @@ struct WasiConsoleMemoryOverride { } unsafe extern "C" fn wasi_console_io_override_read_memory( - ptr: *mut c_char, /* = *WasiConsoleMemoryOverride */ + ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ byte_ptr: *mut c_char, /* &[u8] bytes to read */ @@ -358,9 +367,9 @@ unsafe extern "C" fn wasi_console_io_override_read_memory( } unsafe extern "C" fn wasi_console_io_override_write_memory( - ptr: *mut c_char, /* = *WasiConsoleMemoryOverride */ - sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ - alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ + sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ + alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ byte_ptr: *const c_char, byte_len: usize, flush: bool, @@ -394,9 +403,9 @@ unsafe extern "C" fn wasi_console_io_override_write_memory( } unsafe extern "C" fn wasi_console_io_override_seek_memory( - ptr: *mut c_char, /* = *WasiConsoleMemoryOverride */ - sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ - alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ + sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ + alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ direction: c_char, seek_to: i64, ) -> i64 { @@ -434,9 +443,9 @@ unsafe extern "C" fn wasi_console_io_override_seek_memory( } unsafe extern "C" fn wasi_console_io_override_delete_memory( - ptr: *mut c_char, /* = *WasiConsoleMemoryOverride */ - sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ - alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ + sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ + alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ ) -> i64 { if sizeof != std::mem::size_of::() || alignof != std::mem::align_of::() @@ -444,8 +453,9 @@ unsafe extern "C" fn wasi_console_io_override_delete_memory( return -1; } let ptr = ptr as *mut WasiConsoleMemoryOverride; - let ptr = &*ptr; - let _: WasiConsoleMemoryOverride = std::mem::transmute_copy(&ptr); + let ptr = &mut *ptr; + ptr.backed = Vec::new(); + ptr.cursor = 0; // dropped here, destructors run here 0 } @@ -458,16 +468,16 @@ pub unsafe extern "C" fn wasi_console_io_override_new_memory() -> *mut wasi_cons let data = WasiConsoleMemoryOverride::default(); let mut data = ManuallyDrop::new(data); + let ptr: &mut WasiConsoleMemoryOverride = &mut data; wasi_console_io_override_new( wasi_console_io_override_read_memory, wasi_console_io_override_write_memory, wasi_console_io_override_seek_memory, wasi_console_io_override_delete_memory, - &mut data as *mut _ as *mut i8, + ptr as *mut _ as *mut i8, std::mem::size_of::(), std::mem::align_of::(), - true, ) } @@ -496,13 +506,13 @@ pub unsafe extern "C" fn wasi_console_io_override_write_bytes( #[no_mangle] pub unsafe extern "C" fn wasi_console_io_override_write_str( - ptr: *mut wasi_console_io_override_t, + ptr: *const wasi_console_io_override_t, buf: *const c_char, ) -> i64 { use std::io::Write; let c_str = std::ffi::CStr::from_ptr(buf); let as_bytes_with_nul = c_str.to_bytes(); - let ptr = &mut *ptr; + let ptr = &mut *(ptr as *mut wasi_console_io_override_t); match ptr.write(as_bytes_with_nul) { Ok(o) => o as i64, Err(_) => -1, @@ -523,12 +533,12 @@ pub unsafe extern "C" fn wasi_console_io_override_flush( #[no_mangle] pub unsafe extern "C" fn wasi_console_io_override_read_bytes( - ptr: *mut wasi_console_io_override_t, - buf: *mut c_char, + ptr: *const wasi_console_io_override_t, + buf: *const c_char, read: usize, ) -> i64 { use std::io::Read; - let ptr = &mut *ptr; + let ptr = &mut *(ptr as *mut wasi_console_io_override_t); let buf = buf as *mut u8; let slice = std::slice::from_raw_parts_mut(buf, read); match ptr.read(slice) { @@ -545,7 +555,7 @@ pub unsafe extern "C" fn wasi_console_io_override_delete_str(buf: *mut c_char) { #[no_mangle] pub unsafe extern "C" fn wasi_console_io_override_read_str( - ptr: *mut wasi_console_io_override_t, + ptr: *const wasi_console_io_override_t, buf: *mut *mut c_char, ) -> i64 { use std::ffi::CString; @@ -554,7 +564,7 @@ pub unsafe extern "C" fn wasi_console_io_override_read_str( const BLOCK_SIZE: usize = 1024; let mut target = Vec::new(); - let ptr = &mut *ptr; + let ptr = &mut *(ptr as *mut wasi_console_io_override_t); loop { let mut v = vec![0; BLOCK_SIZE]; From 127e06d8077e7469ae81d095cbc3f8588845da58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 29 Jul 2022 15:40:49 +0200 Subject: [PATCH 08/65] Rename "wasi_console_io_override_t" to "wasi_console_out_t" --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 180 +++++++++++++-------------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 4e1c0b6be35..52ab9e4aa02 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -52,7 +52,7 @@ pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void, usize, #[allow(non_camel_case_types)] #[repr(C)] #[derive(Clone)] -pub struct wasi_console_io_override_t { +pub struct wasi_console_out_t { read: WasiConsoleIoReadCallback, write: WasiConsoleIoWriteCallback, seek: WasiConsoleIoSeekCallback, @@ -62,7 +62,7 @@ pub struct wasi_console_io_override_t { dropped: bool, } -impl wasi_console_io_override_t { +impl wasi_console_out_t { fn get_data_mut(&mut self, op_id: &'static str) -> io::Result>> { self.data .as_mut() @@ -70,7 +70,7 @@ impl wasi_console_io_override_t { io::Error::new( io::ErrorKind::Other, format!( - "could not lock mutex ({op_id}) on wasi_console_io_override_t: no mutex" + "could not lock mutex ({op_id}) on wasi_console_out_t: no mutex" ), ) })? @@ -78,13 +78,13 @@ impl wasi_console_io_override_t { .map_err(|e| { io::Error::new( io::ErrorKind::Other, - format!("could not lock mutex ({op_id}) on wasi_console_io_override_t: {e}"), + format!("could not lock mutex ({op_id}) on wasi_console_out_t: {e}"), ) }) } } -impl Drop for wasi_console_io_override_t { +impl Drop for wasi_console_out_t { fn drop(&mut self) { let align = self.align; let data = match self.data.take() { @@ -120,20 +120,20 @@ impl Drop for wasi_console_io_override_t { ) }; if error < 0 { - println!("error dropping wasi_console_io_override_t: {error}"); + println!("error dropping wasi_console_out_t: {error}"); } self.dropped = true; } } -impl fmt::Debug for wasi_console_io_override_t { +impl fmt::Debug for wasi_console_out_t { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "wasi_console_io_override_t") + write!(f, "wasi_console_out_t") } } -impl io::Read for wasi_console_io_override_t { +impl io::Read for wasi_console_out_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { let self_read = self.read.clone(); let self_align = self.align; @@ -152,13 +152,13 @@ impl io::Read for wasi_console_io_override_t { } else { Err(io::Error::new( io::ErrorKind::Other, - format!("could not read from wasi_console_io_override_t: {result}"), + format!("could not read from wasi_console_out_t: {result}"), )) } } } -impl io::Write for wasi_console_io_override_t { +impl io::Write for wasi_console_out_t { fn write(&mut self, buf: &[u8]) -> io::Result { let self_write = self.write.clone(); let self_align = self.align; @@ -179,7 +179,7 @@ impl io::Write for wasi_console_io_override_t { Err(std::io::Error::new( std::io::ErrorKind::Other, format!( - "could not write {} bytes to wasi_console_io_override_t: {result}", + "could not write {} bytes to wasi_console_out_t: {result}", buf.len() ), )) @@ -205,13 +205,13 @@ impl io::Write for wasi_console_io_override_t { } else { Err(std::io::Error::new( std::io::ErrorKind::Other, - format!("could not flush wasi_console_io_override_t: {result}"), + format!("could not flush wasi_console_out_t: {result}"), )) } } } -impl io::Seek for wasi_console_io_override_t { +impl io::Seek for wasi_console_out_t { fn seek(&mut self, pos: SeekFrom) -> io::Result { let self_seek = self.seek.clone(); let self_align = self.align; @@ -235,13 +235,13 @@ impl io::Seek for wasi_console_io_override_t { } else { Err(std::io::Error::new( std::io::ErrorKind::Other, - format!("could not seek to {pos:?} wasi_console_io_override_t: {result}"), + format!("could not seek to {pos:?} wasi_console_out_t: {result}"), )) } } } -impl VirtualFile for wasi_console_io_override_t { +impl VirtualFile for wasi_console_out_t { fn last_accessed(&self) -> u64 { 0 } @@ -264,7 +264,7 @@ impl VirtualFile for wasi_console_io_override_t { /// Creates a new callback object that is being #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_new( +pub unsafe extern "C" fn wasi_console_out_new( read: WasiConsoleIoReadCallback, write: WasiConsoleIoWriteCallback, seek: WasiConsoleIoSeekCallback, @@ -272,10 +272,10 @@ pub unsafe extern "C" fn wasi_console_io_override_new( env_data: *const c_char, env_data_len: usize, env_data_align: usize, -) -> *mut wasi_console_io_override_t { +) -> *mut wasi_console_out_t { let data_vec: Vec = std::slice::from_raw_parts(env_data, env_data_len).to_vec(); - Box::leak(Box::new(wasi_console_io_override_t { + Box::leak(Box::new(wasi_console_out_t { read, write, seek, @@ -286,23 +286,23 @@ pub unsafe extern "C" fn wasi_console_io_override_new( })) } -/// Creates a `wasi_console_io_override_t` callback object that does nothing +/// Creates a `wasi_console_out_t` callback object that does nothing /// and redirects stdout / stderr to /dev/null #[no_mangle] -pub unsafe extern "C" fn wasi_console_override_new_null() -> *mut wasi_console_io_override_t { +pub unsafe extern "C" fn wasi_console_out_new_null() -> *mut wasi_console_out_t { let mut data = Vec::new(); - wasi_console_io_override_new( - wasi_console_io_override_read_null, - wasi_console_io_override_write_null, - wasi_console_io_override_seek_null, - wasi_console_io_override_delete_null, + wasi_console_out_new( + wasi_console_out_read_null, + wasi_console_out_write_null, + wasi_console_out_seek_null, + wasi_console_out_delete_null, data.as_mut_ptr(), data.len(), std::mem::align_of_val(&data), ) } -extern "C" fn wasi_console_io_override_read_null( +extern "C" fn wasi_console_out_read_null( _: *const c_void, _: usize, _: usize, @@ -311,7 +311,7 @@ extern "C" fn wasi_console_io_override_read_null( ) -> i64 { 0 } -extern "C" fn wasi_console_io_override_write_null( +extern "C" fn wasi_console_out_write_null( _: *const c_void, _: usize, _: usize, @@ -321,7 +321,7 @@ extern "C" fn wasi_console_io_override_write_null( ) -> i64 { 0 } -extern "C" fn wasi_console_io_override_seek_null( +extern "C" fn wasi_console_out_seek_null( _: *const c_void, _: usize, _: usize, @@ -331,7 +331,7 @@ extern "C" fn wasi_console_io_override_seek_null( 0 } -extern "C" fn wasi_console_io_override_delete_null(_: *const c_void, _: usize, _: usize) -> i64 { +extern "C" fn wasi_console_out_delete_null(_: *const c_void, _: usize, _: usize) -> i64 { 0 } @@ -341,7 +341,7 @@ struct WasiConsoleMemoryOverride { cursor: usize, } -unsafe extern "C" fn wasi_console_io_override_read_memory( +unsafe extern "C" fn wasi_console_out_read_memory( ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ @@ -366,7 +366,7 @@ unsafe extern "C" fn wasi_console_io_override_read_memory( read as i64 } -unsafe extern "C" fn wasi_console_io_override_write_memory( +unsafe extern "C" fn wasi_console_out_write_memory( ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ @@ -402,7 +402,7 @@ unsafe extern "C" fn wasi_console_io_override_write_memory( written as i64 } -unsafe extern "C" fn wasi_console_io_override_seek_memory( +unsafe extern "C" fn wasi_console_out_seek_memory( ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ @@ -442,7 +442,7 @@ unsafe extern "C" fn wasi_console_io_override_seek_memory( } } -unsafe extern "C" fn wasi_console_io_override_delete_memory( +unsafe extern "C" fn wasi_console_out_delete_memory( ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ @@ -460,21 +460,21 @@ unsafe extern "C" fn wasi_console_io_override_delete_memory( 0 } -/// Creates a new `wasi_console_io_override_t` which uses a memory buffer +/// Creates a new `wasi_console_out_t` which uses a memory buffer /// for backing stdin / stdout / stderr #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_new_memory() -> *mut wasi_console_io_override_t { +pub unsafe extern "C" fn wasi_console_out_new_memory() -> *mut wasi_console_out_t { use std::mem::ManuallyDrop; let data = WasiConsoleMemoryOverride::default(); let mut data = ManuallyDrop::new(data); let ptr: &mut WasiConsoleMemoryOverride = &mut data; - wasi_console_io_override_new( - wasi_console_io_override_read_memory, - wasi_console_io_override_write_memory, - wasi_console_io_override_seek_memory, - wasi_console_io_override_delete_memory, + wasi_console_out_new( + wasi_console_out_read_memory, + wasi_console_out_write_memory, + wasi_console_out_seek_memory, + wasi_console_out_delete_memory, ptr as *mut _ as *mut i8, std::mem::size_of::(), std::mem::align_of::(), @@ -482,16 +482,16 @@ pub unsafe extern "C" fn wasi_console_io_override_new_memory() -> *mut wasi_cons } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_delete( - ptr: *mut wasi_console_io_override_t, +pub unsafe extern "C" fn wasi_console_out_delete( + ptr: *mut wasi_console_out_t, ) -> bool { let _ = Box::from_raw(ptr); true } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_write_bytes( - ptr: *mut wasi_console_io_override_t, +pub unsafe extern "C" fn wasi_console_out_write_bytes( + ptr: *mut wasi_console_out_t, buf: *const c_char, len: usize, ) -> i64 { @@ -505,14 +505,14 @@ pub unsafe extern "C" fn wasi_console_io_override_write_bytes( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_write_str( - ptr: *const wasi_console_io_override_t, +pub unsafe extern "C" fn wasi_console_out_write_str( + ptr: *const wasi_console_out_t, buf: *const c_char, ) -> i64 { use std::io::Write; let c_str = std::ffi::CStr::from_ptr(buf); let as_bytes_with_nul = c_str.to_bytes(); - let ptr = &mut *(ptr as *mut wasi_console_io_override_t); + let ptr = &mut *(ptr as *mut wasi_console_out_t); match ptr.write(as_bytes_with_nul) { Ok(o) => o as i64, Err(_) => -1, @@ -520,8 +520,8 @@ pub unsafe extern "C" fn wasi_console_io_override_write_str( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_flush( - ptr: *mut wasi_console_io_override_t, +pub unsafe extern "C" fn wasi_console_out_flush( + ptr: *mut wasi_console_out_t, ) -> i64 { use std::io::Write; let ptr = &mut *ptr; @@ -532,13 +532,13 @@ pub unsafe extern "C" fn wasi_console_io_override_flush( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_read_bytes( - ptr: *const wasi_console_io_override_t, +pub unsafe extern "C" fn wasi_console_out_read_bytes( + ptr: *const wasi_console_out_t, buf: *const c_char, read: usize, ) -> i64 { use std::io::Read; - let ptr = &mut *(ptr as *mut wasi_console_io_override_t); + let ptr = &mut *(ptr as *mut wasi_console_out_t); let buf = buf as *mut u8; let slice = std::slice::from_raw_parts_mut(buf, read); match ptr.read(slice) { @@ -548,14 +548,14 @@ pub unsafe extern "C" fn wasi_console_io_override_read_bytes( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_delete_str(buf: *mut c_char) { +pub unsafe extern "C" fn wasi_console_out_delete_str(buf: *mut c_char) { use std::ffi::CString; let _ = CString::from_raw(buf); } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_read_str( - ptr: *const wasi_console_io_override_t, +pub unsafe extern "C" fn wasi_console_out_read_str( + ptr: *const wasi_console_out_t, buf: *mut *mut c_char, ) -> i64 { use std::ffi::CString; @@ -564,7 +564,7 @@ pub unsafe extern "C" fn wasi_console_io_override_read_str( const BLOCK_SIZE: usize = 1024; let mut target = Vec::new(); - let ptr = &mut *(ptr as *mut wasi_console_io_override_t); + let ptr = &mut *(ptr as *mut wasi_console_out_t); loop { let mut v = vec![0; BLOCK_SIZE]; @@ -596,8 +596,8 @@ pub unsafe extern "C" fn wasi_console_io_override_read_str( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_seek( - ptr: *mut wasi_console_io_override_t, +pub unsafe extern "C" fn wasi_console_out_seek( + ptr: *mut wasi_console_out_t, // 0 = from start // 1 = from end // 2 = from current position @@ -624,18 +624,18 @@ pub unsafe extern "C" fn wasi_console_io_override_seek( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_io_override_clone( - ptr: *const wasi_console_io_override_t, -) -> *mut wasi_console_io_override_t { +pub unsafe extern "C" fn wasi_console_out_clone( + ptr: *const wasi_console_out_t, +) -> *mut wasi_console_out_t { Box::leak(Box::new((&*ptr).clone())) } #[derive(Debug)] #[allow(non_camel_case_types)] pub struct wasi_config_t { - inherit_stdout: Option>, - inherit_stderr: Option>, - inherit_stdin: Option>, + inherit_stdout: Option>, + inherit_stderr: Option>, + inherit_stdin: Option>, state_builder: WasiStateBuilder, } @@ -742,7 +742,7 @@ pub unsafe extern "C" fn wasi_config_mapdir( #[no_mangle] pub extern "C" fn wasi_config_capture_stdout(config: &mut wasi_config_t) { - config.inherit_stdout = Some(unsafe { Box::from_raw(wasi_console_override_new_null()) }); + config.inherit_stdout = Some(unsafe { Box::from_raw(wasi_console_out_new_null()) }); } #[no_mangle] @@ -752,7 +752,7 @@ pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { #[no_mangle] pub extern "C" fn wasi_config_capture_stderr(config: &mut wasi_config_t) { - config.inherit_stderr = Some(unsafe { Box::from_raw(wasi_console_override_new_null()) }); + config.inherit_stderr = Some(unsafe { Box::from_raw(wasi_console_out_new_null()) }); } #[no_mangle] @@ -762,7 +762,7 @@ pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { #[no_mangle] pub extern "C" fn wasi_config_capture_stdin(config: &mut wasi_config_t) { - config.inherit_stdin = Some(unsafe { Box::from_raw(wasi_console_override_new_null()) }); + config.inherit_stdin = Some(unsafe { Box::from_raw(wasi_console_out_new_null()) }); } #[no_mangle] @@ -773,7 +773,7 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdin( config: &mut wasi_config_t, - stdin: *mut wasi_console_io_override_t, + stdin: *mut wasi_console_out_t, ) { config.state_builder.stdin(Box::from_raw(stdin)); } @@ -781,7 +781,7 @@ pub unsafe extern "C" fn wasi_config_overwrite_stdin( #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdout( config: &mut wasi_config_t, - stdout: *mut wasi_console_io_override_t, + stdout: *mut wasi_console_out_t, ) { config.state_builder.stdout(Box::from_raw(stdout)); } @@ -789,7 +789,7 @@ pub unsafe extern "C" fn wasi_config_overwrite_stdout( #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stderr( config: &mut wasi_config_t, - stderr: *mut wasi_console_io_override_t, + stderr: *mut wasi_console_out_t, ) { config.state_builder.stderr(Box::from_raw(stderr)); } @@ -1056,15 +1056,15 @@ mod tests { wasm_store_t* store = wasm_store_new(engine); wasi_config_t* config = wasi_config_new("example_program"); - wasi_console_io_override_t* override_stdin = wasi_console_io_override_new_memory(); - wasi_console_io_override_t* override_stdout = wasi_console_io_override_new_memory(); - wasi_console_io_override_t* override_stderr = wasi_console_io_override_new_memory(); + wasi_console_out_t* override_stdin = wasi_console_out_new_memory(); + wasi_console_out_t* override_stdout = wasi_console_out_new_memory(); + wasi_console_out_t* override_stderr = wasi_console_out_new_memory(); - // Cloning the `wasi_console_io_override_t` does not deep-clone the + // Cloning the `wasi_console_out_t` does not deep-clone the // internal stream, since that is locked behind an Arc>. - wasi_console_io_override_t* stdin_sender = wasi_console_io_override_clone(override_stdin); - wasi_console_io_override_t* stdout_receiver = wasi_console_io_override_clone(override_stdout); - wasi_console_io_override_t* stderr_receiver = wasi_console_io_override_clone(override_stderr); + wasi_console_out_t* stdin_sender = wasi_console_out_clone(override_stdin); + wasi_console_out_t* stdout_receiver = wasi_console_out_clone(override_stdout); + wasi_console_out_t* stderr_receiver = wasi_console_out_clone(override_stderr); // The override_stdin ownership is moved to the config wasi_config_overwrite_stdin(config, override_stdin); @@ -1103,33 +1103,33 @@ mod tests { // The program should wait for a stdin, then print "stdout: $1" to stdout // and "stderr: $1" to stderr and exit. - wasi_console_io_override_write_str(stdin_sender, "hello"); + wasi_console_out_write_str(stdin_sender, "hello"); char* out; - wasi_console_io_override_read_str(stdout_receiver, &out); + wasi_console_out_read_str(stdout_receiver, &out); printf("stdout 1: \"%s\"\n", out); assert(strcmp(out, "stdout: hello") == 0); - wasi_console_io_override_delete_str(out); + wasi_console_out_delete_str(out); - wasi_console_io_override_read_str(stdout_receiver, &out); + wasi_console_out_read_str(stdout_receiver, &out); printf("stdout 2: \"%s\"\n", out); assert(strcmp(out, "")); - wasi_console_io_override_delete_str(out); + wasi_console_out_delete_str(out); - wasi_console_io_override_read_str(stderr_receiver, &out); + wasi_console_out_read_str(stderr_receiver, &out); printf("stdout 3: \"%s\"\n", out); assert(strcmp(out, "stderr: hello")); - wasi_console_io_override_delete_str(out); + wasi_console_out_delete_str(out); - wasi_console_io_override_read_str(stderr_receiver, &out); + wasi_console_out_read_str(stderr_receiver, &out); printf("stdout 4: \"%s\"\n", out); assert(strcmp(out, "")); - wasi_console_io_override_delete_str(out); + wasi_console_out_delete_str(out); - wasi_console_io_override_delete(stdin_sender); - wasi_console_io_override_delete(stdout_receiver); - wasi_console_io_override_delete(stderr_receiver); + wasi_console_out_delete(stdin_sender); + wasi_console_out_delete(stdout_receiver); + wasi_console_out_delete(stderr_receiver); free(buffer); wasm_module_delete(module); From 5103306eccf0ec7d58daa18439da829036c183f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 1 Aug 2022 13:23:03 +0200 Subject: [PATCH 09/65] Added API for wasi_stdin_t --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 211 +++++++++++++++++++++++++-- 1 file changed, 200 insertions(+), 11 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 52ab9e4aa02..9fe513484a1 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -39,7 +39,23 @@ pub type WasiConsoleIoWriteCallback = unsafe extern "C" fn(*const c_void, usize, usize, *const c_char, usize, bool) -> i64; pub type WasiConsoleIoSeekCallback = unsafe extern "C" fn(*const c_void, usize, usize, c_char, i64) -> i64; -pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void, usize, usize) -> i64; +pub type WasiConsoleIoEnvDestructor = + unsafe extern "C" fn(*const c_void, usize, usize) -> i64; +/// Callback that is activated whenever the program wants to read from stdin +/// +/// Parameters: +/// - `void*`: to user-defined data +/// - `usize`: sizeof(user-defined data) +/// - `usize`: alignof(user-defined data) +/// - `usize`: maximum bytes that can be written to stdin +/// - `*mut wasi_console_stdin_response_t`: handle to the stdin response, used to write data to stdin +/// +/// The function returning is the same as the program receiving an "enter" +/// key event from the console I/O. With the custom environment pointer (the first argument) +/// you can clone references to the stdout channel and - for example - inspect the stdout +/// channel to answer depending on runtime-dependent stdout data. +pub type WasiConsoleIoOnStdinCallback = + unsafe extern "C" fn(*const c_void, usize, usize, usize, *mut wasi_console_stdin_response_t) -> i64; /// The console override is a custom context consisting of callback pointers /// (which are activated whenever some console I/O occurs) and a "context", which @@ -59,7 +75,6 @@ pub struct wasi_console_out_t { destructor: WasiConsoleIoEnvDestructor, data: Option>>>>, align: usize, - dropped: bool, } impl wasi_console_out_t { @@ -108,10 +123,6 @@ impl Drop for wasi_console_out_t { } }; - if self.dropped { - return; - } - let error = unsafe { (self.destructor)( inner_value.as_mut_ptr() as *const c_void, @@ -122,8 +133,6 @@ impl Drop for wasi_console_out_t { if error < 0 { println!("error dropping wasi_console_out_t: {error}"); } - - self.dropped = true; } } @@ -252,7 +261,7 @@ impl VirtualFile for wasi_console_out_t { 0 } fn size(&self) -> u64 { - 0 + u64::MAX } fn set_len(&mut self, _: u64) -> Result<(), FsError> { Ok(()) @@ -282,7 +291,6 @@ pub unsafe extern "C" fn wasi_console_out_new( destructor, data: Some(Box::new(Arc::new(Mutex::new(data_vec)))), align: env_data_align, - dropped: false, })) } @@ -770,10 +778,191 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { config.inherit_stdin = None; } +#[repr(C)] +pub struct wasi_console_stdin_t { + on_stdin: WasiConsoleIoOnStdinCallback, + destructor: WasiConsoleIoEnvDestructor, + data: Option>>, + align: usize, +} + +impl wasi_console_stdin_t { + fn get_data_mut(&mut self, op_id: &'static str) -> io::Result<&mut Vec> { + self.data + .as_mut() + .map(|s| &mut (**s)) + .ok_or({ + io::Error::new( + io::ErrorKind::Other, + format!( + "could not get env data ({op_id}) on wasi_console_stdin_t" + ), + ) + }) + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_stdin_new( + on_stdin: WasiConsoleIoOnStdinCallback, + destructor: WasiConsoleIoEnvDestructor, + ptr: *const c_void, + len: usize, + align: usize, +) -> *mut wasi_console_stdin_t { + let data = std::slice::from_raw_parts(ptr as *const c_char, len); + Box::leak(Box::new(wasi_console_stdin_t { + on_stdin, + destructor, + data: Some(Box::new(data.to_vec())), + align, + })) +} + +impl Drop for wasi_console_stdin_t { + fn drop(&mut self) { + let align = self.align; + let mut data = match self.data.take() { + Some(s) => s, + None => { + return; + } + }; + + let error = unsafe { + (self.destructor)( + (*data).as_mut_ptr() as *const c_void, + (*data).len(), + align, + ) + }; + + if error < 0 { + println!("error dropping wasi_console_stdin_t: {error}"); + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_stdin_delete( + ptr: *mut wasi_console_stdin_t, +) -> bool { + let _ = Box::from_raw(ptr); + true +} + +#[derive(Clone)] +#[repr(C)] +pub struct wasi_console_stdin_response_t { + // data that is written to the response + response_data: Box>, +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_stdin_response_write_bytes( + response_t: &mut wasi_console_stdin_response_t, + bytes: *const c_char, + len: usize, +) -> i64 { + let slice = std::slice::from_raw_parts(bytes, len); + let bytes_to_extend = response_t.response_data.len() as i64 - slice.len() as i64; + if bytes_to_extend > 0 { + response_t.response_data.append(&mut vec![0; bytes_to_extend as usize]); + } + for (source, target) in slice.iter().zip(response_t.response_data.iter_mut()) { + *target = *source; + } + slice.len() as i64 +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_console_stdin_response_write_str( + response_t: &mut wasi_console_stdin_response_t, + str: *const c_char, +) -> i64 { + let c_str = CStr::from_ptr(str); + let bytes = c_str.to_bytes(); + wasi_console_stdin_response_write_bytes(response_t, bytes.as_ptr() as *const c_char, bytes.len()) +} + +impl fmt::Debug for wasi_console_stdin_t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "wasi_console_stdin_t") + } +} + +impl io::Read for wasi_console_stdin_t { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut target = wasi_console_stdin_response_t { + response_data: Box::new(Vec::new()), + }; + let self_align = self.align; + let self_on_stdin = self.on_stdin; + let data = self.get_data_mut("read")?; + let result = unsafe { + (self_on_stdin)( + data.as_ptr() as *const c_void, + data.len(), + self_align, + buf.len(), + &mut target, + ) + }; + + if result >= 0 { + for (source, target) in target.response_data.iter().zip(buf.iter_mut()) { + *target = *source as u8; + } + Ok(result as usize) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + format!("could not read from wasi_console_out_t: {result}"), + )) + } + } +} + +impl io::Write for wasi_console_stdin_t { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl io::Seek for wasi_console_stdin_t { + fn seek(&mut self, _: SeekFrom) -> io::Result { + Ok(0) + } +} + +impl VirtualFile for wasi_console_stdin_t { + fn last_accessed(&self) -> u64 { + 0 + } + fn last_modified(&self) -> u64 { + 0 + } + fn created_time(&self) -> u64 { + 0 + } + fn size(&self) -> u64 { + u64::MAX + } + fn set_len(&mut self, _: u64) -> Result<(), FsError> { + Ok(()) + } + fn unlink(&mut self) -> Result<(), FsError> { + Ok(()) + } +} + #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdin( config: &mut wasi_config_t, - stdin: *mut wasi_console_out_t, + stdin: *mut wasi_console_stdin_t, ) { config.state_builder.stdin(Box::from_raw(stdin)); } From 8c36f06c3ebfca10f6c79a4a04b37c54fec93c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 1 Aug 2022 15:16:52 +0200 Subject: [PATCH 10/65] Finalize API for stdin API rewrite --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 202 ++++++++++++++++++--------- 1 file changed, 135 insertions(+), 67 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 9fe513484a1..bccb5d3b48c 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -39,23 +39,27 @@ pub type WasiConsoleIoWriteCallback = unsafe extern "C" fn(*const c_void, usize, usize, *const c_char, usize, bool) -> i64; pub type WasiConsoleIoSeekCallback = unsafe extern "C" fn(*const c_void, usize, usize, c_char, i64) -> i64; -pub type WasiConsoleIoEnvDestructor = - unsafe extern "C" fn(*const c_void, usize, usize) -> i64; +pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void, usize, usize) -> i64; /// Callback that is activated whenever the program wants to read from stdin -/// +/// /// Parameters: /// - `void*`: to user-defined data /// - `usize`: sizeof(user-defined data) /// - `usize`: alignof(user-defined data) /// - `usize`: maximum bytes that can be written to stdin /// - `*mut wasi_console_stdin_response_t`: handle to the stdin response, used to write data to stdin -/// -/// The function returning is the same as the program receiving an "enter" +/// +/// The function returning is the same as the program receiving an "enter" /// key event from the console I/O. With the custom environment pointer (the first argument) /// you can clone references to the stdout channel and - for example - inspect the stdout /// channel to answer depending on runtime-dependent stdout data. -pub type WasiConsoleIoOnStdinCallback = - unsafe extern "C" fn(*const c_void, usize, usize, usize, *mut wasi_console_stdin_response_t) -> i64; +pub type WasiConsoleIoOnStdinCallback = unsafe extern "C" fn( + *const c_void, + usize, + usize, + usize, + *mut wasi_console_stdin_response_t, +) -> i64; /// The console override is a custom context consisting of callback pointers /// (which are activated whenever some console I/O occurs) and a "context", which @@ -84,9 +88,7 @@ impl wasi_console_out_t { .ok_or({ io::Error::new( io::ErrorKind::Other, - format!( - "could not lock mutex ({op_id}) on wasi_console_out_t: no mutex" - ), + format!("could not lock mutex ({op_id}) on wasi_console_out_t: no mutex"), ) })? .lock() @@ -490,9 +492,7 @@ pub unsafe extern "C" fn wasi_console_out_new_memory() -> *mut wasi_console_out_ } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_delete( - ptr: *mut wasi_console_out_t, -) -> bool { +pub unsafe extern "C" fn wasi_console_out_delete(ptr: *mut wasi_console_out_t) -> bool { let _ = Box::from_raw(ptr); true } @@ -528,9 +528,7 @@ pub unsafe extern "C" fn wasi_console_out_write_str( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_flush( - ptr: *mut wasi_console_out_t, -) -> i64 { +pub unsafe extern "C" fn wasi_console_out_flush(ptr: *mut wasi_console_out_t) -> i64 { use std::io::Write; let ptr = &mut *ptr; match ptr.flush() { @@ -788,17 +786,12 @@ pub struct wasi_console_stdin_t { impl wasi_console_stdin_t { fn get_data_mut(&mut self, op_id: &'static str) -> io::Result<&mut Vec> { - self.data - .as_mut() - .map(|s| &mut (**s)) - .ok_or({ - io::Error::new( - io::ErrorKind::Other, - format!( - "could not get env data ({op_id}) on wasi_console_stdin_t" - ), - ) - }) + self.data.as_mut().map(|s| &mut (**s)).ok_or({ + io::Error::new( + io::ErrorKind::Other, + format!("could not get env data ({op_id}) on wasi_console_stdin_t"), + ) + }) } } @@ -830,11 +823,7 @@ impl Drop for wasi_console_stdin_t { }; let error = unsafe { - (self.destructor)( - (*data).as_mut_ptr() as *const c_void, - (*data).len(), - align, - ) + (self.destructor)((*data).as_mut_ptr() as *const c_void, (*data).len(), align) }; if error < 0 { @@ -844,9 +833,7 @@ impl Drop for wasi_console_stdin_t { } #[no_mangle] -pub unsafe extern "C" fn wasi_console_stdin_delete( - ptr: *mut wasi_console_stdin_t, -) -> bool { +pub unsafe extern "C" fn wasi_console_stdin_delete(ptr: *mut wasi_console_stdin_t) -> bool { let _ = Box::from_raw(ptr); true } @@ -867,7 +854,9 @@ pub unsafe extern "C" fn wasi_console_stdin_response_write_bytes( let slice = std::slice::from_raw_parts(bytes, len); let bytes_to_extend = response_t.response_data.len() as i64 - slice.len() as i64; if bytes_to_extend > 0 { - response_t.response_data.append(&mut vec![0; bytes_to_extend as usize]); + response_t + .response_data + .append(&mut vec![0; bytes_to_extend as usize]); } for (source, target) in slice.iter().zip(response_t.response_data.iter_mut()) { *target = *source; @@ -882,7 +871,11 @@ pub unsafe extern "C" fn wasi_console_stdin_response_write_str( ) -> i64 { let c_str = CStr::from_ptr(str); let bytes = c_str.to_bytes(); - wasi_console_stdin_response_write_bytes(response_t, bytes.as_ptr() as *const c_char, bytes.len()) + wasi_console_stdin_response_write_bytes( + response_t, + bytes.as_ptr() as *const c_char, + bytes.len(), + ) } impl fmt::Debug for wasi_console_stdin_t { @@ -1239,19 +1232,58 @@ mod tests { #include "tests/wasmer.h" #include "string.h" #include "stdio.h" + #include "stdalign.h" + + typedef struct { + int u; + } CustomWasiStdin; + + long CustomWasiStdin_destructor( + const void* env, + __u_long sz, + __u_long ao + ) { + (void)env; + (void)sz; + (void)ao; + return 0; + } + + long CustomWasiStdin_onStdIn( + const void* env, + __u_long sz, + __u_long ao, + __u_long maxwrite, + wasi_console_stdin_response_t* in + ) { + (void)env; + (void)sz; + (void)ao; + (void)maxwrite; + + wasi_console_stdin_response_write_str(in, "hello"); + return 5; + } int main() { + wasm_engine_t* engine = wasm_engine_new(); wasm_store_t* store = wasm_store_new(engine); wasi_config_t* config = wasi_config_new("example_program"); - wasi_console_out_t* override_stdin = wasi_console_out_new_memory(); wasi_console_out_t* override_stdout = wasi_console_out_new_memory(); wasi_console_out_t* override_stderr = wasi_console_out_new_memory(); - - // Cloning the `wasi_console_out_t` does not deep-clone the + CustomWasiStdin stdin = { .u = 0 }; + wasi_console_stdin_t* override_stdin = wasi_console_stdin_new( + CustomWasiStdin_onStdIn, + CustomWasiStdin_destructor, + &stdin, + sizeof(stdin), + alignof(stdin) + ); + + // Cloning the `wasi_console_out_t` does not deep-clone the // internal stream, since that is locked behind an Arc>. - wasi_console_out_t* stdin_sender = wasi_console_out_clone(override_stdin); wasi_console_out_t* stdout_receiver = wasi_console_out_clone(override_stdout); wasi_console_out_t* stderr_receiver = wasi_console_out_clone(override_stderr); @@ -1263,39 +1295,77 @@ mod tests { // The env now has ownership of the config (using the custom stdout / stdin channels) wasmer_funcenv_t* env = wasmer_funcenv_new(store, config); - FILE *fileptr; - char *buffer; - long filelen; + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + + fclose(file); - fileptr = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); - if (!fileptr) { - assert(false); // file not found + printf("Compiling module...\n"); + wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; } - fseek(fileptr, 0, SEEK_END); - filelen = ftell(fileptr); - rewind(fileptr); + wasm_byte_vec_delete(&binary); + + // The program should wait for a stdin, then print "stdout: $1" to stdout + // and "stderr: $1" to stderr and exit. - buffer = (char *)malloc(filelen * sizeof(char)); - if (!fread(buffer, filelen, 1, fileptr)) { - assert(false); + // Instantiate the moduke + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + wasm_trap_t* trap = NULL; + wasm_instance_t* instance = + wasm_instance_new(store, module, &imports, &trap); + if (instance || !trap) { + printf("> Error instantiating module, expected trap!\n"); + return 1; } - fclose(fileptr); + wasm_module_delete(module); - // convert to wasm_byte_vec_t - wasm_byte_vec_t* wasm = 0; - wasm_byte_vec_new(wasm, filelen, buffer); + /* + if (!wasi_funcenv_initialize_instance(env, store, instance)) { + printf("> Error initializing wasi env memory!\n"); + return 1; + } + */ - wasm_module_t* module = wasm_module_new(store, wasm); - assert(module); + // Get the _start function + wasm_func_t* run_func = wasi_get_start_function(instance); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } - assert(wasi_get_wasi_version(module) == SNAPSHOT0); + printf("got _start\n"); - // The program should wait for a stdin, then print "stdout: $1" to stdout - // and "stderr: $1" to stderr and exit. - wasi_console_out_write_str(stdin_sender, "hello"); + // Run the _start function + // Running the program should trigger the stdin to write "hello" to the stdin + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t res = WASM_EMPTY_VEC; + if (wasm_func_call(run_func, &args, &res)) { + printf("> Error calling function!\n"); + return 1; + } + // Verify that the stdout / stderr worked as expected char* out; - wasi_console_out_read_str(stdout_receiver, &out); printf("stdout 1: \"%s\"\n", out); assert(strcmp(out, "stdout: hello") == 0); @@ -1316,13 +1386,11 @@ mod tests { assert(strcmp(out, "")); wasi_console_out_delete_str(out); - wasi_console_out_delete(stdin_sender); wasi_console_out_delete(stdout_receiver); wasi_console_out_delete(stderr_receiver); - free(buffer); + wasm_func_delete(run_func); wasm_module_delete(module); - wasm_byte_vec_delete(wasm); wasmer_funcenv_delete(env); wasm_store_delete(store); wasm_engine_delete(engine); From dfe4e8e38d0f3624d3104f7cd2855fe5615535b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 1 Aug 2022 18:09:46 +0200 Subject: [PATCH 11/65] Try debuggint unit test test_wasi_stdin_set --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 215 ++++++++++++++++----------- 1 file changed, 132 insertions(+), 83 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index bccb5d3b48c..f5000112341 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -1230,9 +1230,107 @@ mod tests { fn test_wasi_get_wasi_version_snapshot0() { (assert_c! { #include "tests/wasmer.h" + + int main() { + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + wasmer_funcenv_t* env = wasmer_funcenv_new(store, 0); + + wasm_byte_vec_t wat; + wasmer_byte_vec_new_from_string(&wat, "(module (import \"wasi_unstable\" \"args_get\" (func (param i32 i32) (result i32))))"); + wasm_byte_vec_t wasm; + wat2wasm(&wat, &wasm); + + wasm_module_t* module = wasm_module_new(store, &wasm); + assert(module); + + assert(wasi_get_wasi_version(module) == SNAPSHOT0); + + wasm_module_delete(module); + wasm_byte_vec_delete(&wasm); + wasm_byte_vec_delete(&wat); + wasmer_funcenv_delete(env); + wasm_store_delete(store); + wasm_engine_delete(engine); + + return 0; + } + }) + .success(); + } + + #[test] + fn test_wasi_get_wasi_version_snapshot1() { + (assert_c! { + #include "tests/wasmer.h" + + int main() { + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + wasmer_funcenv_t* env = wasmer_funcenv_new(store, 0); + + wasm_byte_vec_t wat; + wasmer_byte_vec_new_from_string(&wat, "(module (import \"wasi_snapshot_preview1\" \"args_get\" (func (param i32 i32) (result i32))))"); + wasm_byte_vec_t wasm; + wat2wasm(&wat, &wasm); + + wasm_module_t* module = wasm_module_new(store, &wasm); + assert(module); + + assert(wasi_get_wasi_version(module) == SNAPSHOT1); + + wasm_module_delete(module); + wasm_byte_vec_delete(&wasm); + wasm_byte_vec_delete(&wat); + wasmer_funcenv_delete(env); + wasm_store_delete(store); + wasm_engine_delete(engine); + + return 0; + } + }) + .success(); + } + + #[test] + fn test_wasi_get_wasi_version_invalid() { + (assert_c! { + #include "tests/wasmer.h" + + int main() { + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + wasmer_funcenv_t* env = wasmer_funcenv_new(store, 0); + + wasm_byte_vec_t wat; + wasmer_byte_vec_new_from_string(&wat, "(module (import \"wasi_snpsht_prvw1\" \"args_get\" (func (param i32 i32) (result i32))))"); + wasm_byte_vec_t wasm; + wat2wasm(&wat, &wasm); + + wasm_module_t* module = wasm_module_new(store, &wasm); + assert(module); + + assert(wasi_get_wasi_version(module) == INVALID_VERSION); + + wasm_module_delete(module); + wasm_byte_vec_delete(&wasm); + wasm_byte_vec_delete(&wat); + wasmer_funcenv_delete(env); + wasm_store_delete(store); + wasm_engine_delete(engine); + + return 0; + } + }) + .success(); + } + + #[test] + fn test_wasi_stdin_set() { + (assert_c! { + #include "../../lib/c-api/wasmer.h" #include "string.h" #include "stdio.h" - #include "stdalign.h" typedef struct { int u; @@ -1268,18 +1366,37 @@ mod tests { int main() { wasm_engine_t* engine = wasm_engine_new(); + if (!engine) { + printf("> Error loading engine!\n"); + return 1; + } wasm_store_t* store = wasm_store_new(engine); + if (!store) { + printf("> Error loading store!\n"); + return 1; + } wasi_config_t* config = wasi_config_new("example_program"); - + if (!config) { + printf("> Error loading config!\n"); + return 1; + } wasi_console_out_t* override_stdout = wasi_console_out_new_memory(); + if (!override_stdout) { + printf("> Error loading override_stdout!\n"); + return 1; + } wasi_console_out_t* override_stderr = wasi_console_out_new_memory(); + if (!override_stderr) { + printf("> Error loading override_stderr!\n"); + return 1; + } CustomWasiStdin stdin = { .u = 0 }; wasi_console_stdin_t* override_stdin = wasi_console_stdin_new( CustomWasiStdin_onStdIn, CustomWasiStdin_destructor, &stdin, sizeof(stdin), - alignof(stdin) + 8 // alignof(stdin) ); // Cloning the `wasi_console_out_t` does not deep-clone the @@ -1293,7 +1410,11 @@ mod tests { wasi_config_overwrite_stderr(config, override_stderr); // The env now has ownership of the config (using the custom stdout / stdin channels) - wasmer_funcenv_t* env = wasmer_funcenv_new(store, config); + wasi_env_t* env = wasi_env_new(store, config); + if (!env) { + printf("> Error loading env!\n"); + return 1; + } // Load binary. printf("Loading binary...\n"); @@ -1323,7 +1444,6 @@ mod tests { printf("> Error compiling module!\n"); return 1; } - wasm_byte_vec_delete(&binary); // The program should wait for a stdin, then print "stdout: $1" to stdout // and "stderr: $1" to stderr and exit. @@ -1331,20 +1451,16 @@ mod tests { // Instantiate the moduke wasm_extern_vec_t imports = WASM_EMPTY_VEC; wasm_trap_t* trap = NULL; - wasm_instance_t* instance = - wasm_instance_new(store, module, &imports, &trap); - if (instance || !trap) { - printf("> Error instantiating module, expected trap!\n"); + wasm_instance_t* instance = wasm_instance_new(store, module, &imports,&trap); + if (!instance) { + printf("> Error instantiating module!\n"); return 1; } - wasm_module_delete(module); - /* - if (!wasi_funcenv_initialize_instance(env, store, instance)) { + if (!wasi_env_initialize_instance(env, store, instance)) { printf("> Error initializing wasi env memory!\n"); return 1; } - */ // Get the _start function wasm_func_t* run_func = wasi_get_start_function(instance); @@ -1353,8 +1469,6 @@ mod tests { return 1; } - printf("got _start\n"); - // Run the _start function // Running the program should trigger the stdin to write "hello" to the stdin wasm_val_vec_t args = WASM_EMPTY_VEC; @@ -1389,75 +1503,10 @@ mod tests { wasi_console_out_delete(stdout_receiver); wasi_console_out_delete(stderr_receiver); - wasm_func_delete(run_func); - wasm_module_delete(module); - wasmer_funcenv_delete(env); - wasm_store_delete(store); - wasm_engine_delete(engine); - - return 0; - } - }) - .success(); - } - - #[test] - fn test_wasi_get_wasi_version_snapshot1() { - (assert_c! { - #include "tests/wasmer.h" - - int main() { - wasm_engine_t* engine = wasm_engine_new(); - wasm_store_t* store = wasm_store_new(engine); - wasmer_funcenv_t* env = wasmer_funcenv_new(store, 0); - - wasm_byte_vec_t wat; - wasmer_byte_vec_new_from_string(&wat, "(module (import \"wasi_snapshot_preview1\" \"args_get\" (func (param i32 i32) (result i32))))"); - wasm_byte_vec_t wasm; - wat2wasm(&wat, &wasm); - - wasm_module_t* module = wasm_module_new(store, &wasm); - assert(module); - - assert(wasi_get_wasi_version(module) == SNAPSHOT1); - - wasm_module_delete(module); - wasm_byte_vec_delete(&wasm); - wasm_byte_vec_delete(&wat); - wasmer_funcenv_delete(env); - wasm_store_delete(store); - wasm_engine_delete(engine); - - return 0; - } - }) - .success(); - } - - #[test] - fn test_wasi_get_wasi_version_invalid() { - (assert_c! { - #include "tests/wasmer.h" - - int main() { - wasm_engine_t* engine = wasm_engine_new(); - wasm_store_t* store = wasm_store_new(engine); - wasmer_funcenv_t* env = wasmer_funcenv_new(store, 0); - - wasm_byte_vec_t wat; - wasmer_byte_vec_new_from_string(&wat, "(module (import \"wasi_snpsht_prvw1\" \"args_get\" (func (param i32 i32) (result i32))))"); - wasm_byte_vec_t wasm; - wat2wasm(&wat, &wasm); - - wasm_module_t* module = wasm_module_new(store, &wasm); - assert(module); - - assert(wasi_get_wasi_version(module) == INVALID_VERSION); - + wasm_byte_vec_delete(&binary); wasm_module_delete(module); - wasm_byte_vec_delete(&wasm); - wasm_byte_vec_delete(&wat); - wasmer_funcenv_delete(env); + wasm_func_delete(run_func); + wasi_env_delete(env); wasm_store_delete(store); wasm_engine_delete(engine); From f4ff4bcde43bbca74f1a32277dccdf9e170fa144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 2 Aug 2022 17:28:57 +0200 Subject: [PATCH 12/65] Fixed stdin-capi unit test not running due to missing imports --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 56 ++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index f5000112341..4fbe30669fe 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -1409,13 +1409,6 @@ mod tests { wasi_config_overwrite_stdout(config, override_stdout); wasi_config_overwrite_stderr(config, override_stderr); - // The env now has ownership of the config (using the custom stdout / stdin channels) - wasi_env_t* env = wasi_env_new(store, config); - if (!env) { - printf("> Error loading env!\n"); - return 1; - } - // Load binary. printf("Loading binary...\n"); FILE* file = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); @@ -1445,22 +1438,53 @@ mod tests { return 1; } + // The env now has ownership of the config (using the custom stdout / stdin channels) + wasi_env_t *wasi_env = wasi_env_new(store, config); + if (!wasi_env) { + printf("> Error building WASI env!\n"); + return 1; + } + + wasm_importtype_vec_t import_types; + wasm_module_imports(module, &import_types); + + wasm_extern_vec_t imports; + wasm_extern_vec_new_uninitialized(&imports, import_types.size); + wasm_importtype_vec_delete(&import_types); + + bool get_imports_result = wasi_get_imports(store, wasi_env, module, &imports); + + if (!get_imports_result) { + printf("Error getting WASI imports!\n"); + return 1; + } + // The program should wait for a stdin, then print "stdout: $1" to stdout // and "stderr: $1" to stderr and exit. - // Instantiate the moduke - wasm_extern_vec_t imports = WASM_EMPTY_VEC; - wasm_trap_t* trap = NULL; - wasm_instance_t* instance = wasm_instance_new(store, module, &imports,&trap); + // Instantiate the module + wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); - return 1; + return -1; } - if (!wasi_env_initialize_instance(env, store, instance)) { - printf("> Error initializing wasi env memory!\n"); - return 1; + // Read the exports. + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + wasm_memory_t* mem = NULL; + for (size_t i = 0; i < exports.size; i++) { + mem = wasm_extern_as_memory(exports.data[i]); + if (mem) { + break; + } + } + + if (!mem) { + printf("Failed to create instance: Could not find memory in exports\n"); + return -1; } + wasi_env_set_memory(wasi_env, mem); // Get the _start function wasm_func_t* run_func = wasi_get_start_function(instance); @@ -1506,7 +1530,7 @@ mod tests { wasm_byte_vec_delete(&binary); wasm_module_delete(module); wasm_func_delete(run_func); - wasi_env_delete(env); + wasi_env_delete(wasi_env); wasm_store_delete(store); wasm_engine_delete(engine); From 5e83b809e2a8409b508f5841007ac38d7851d397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 2 Aug 2022 19:38:54 +0200 Subject: [PATCH 13/65] Fix C-API stdin PR: read correct amount of bytes and fix stdout cursor --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 172 +++++++++++---------------- 1 file changed, 68 insertions(+), 104 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 4fbe30669fe..142b27f4e7e 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -82,10 +82,10 @@ pub struct wasi_console_out_t { } impl wasi_console_out_t { - fn get_data_mut(&mut self, op_id: &'static str) -> io::Result>> { + fn get_data_mut(&self, op_id: &'static str) -> io::Result>> { self.data - .as_mut() - .ok_or({ + .as_ref() + .ok_or_else(|| { io::Error::new( io::ErrorKind::Other, format!("could not lock mutex ({op_id}) on wasi_console_out_t: no mutex"), @@ -263,7 +263,7 @@ impl VirtualFile for wasi_console_out_t { 0 } fn size(&self) -> u64 { - u64::MAX + self.get_data_mut("size").map(|s| s.len() as u64).unwrap_or(0) } fn set_len(&mut self, _: u64) -> Result<(), FsError> { Ok(()) @@ -398,18 +398,8 @@ unsafe extern "C" fn wasi_console_out_write_memory( let ptr = &mut *ptr; let byte_ptr = byte_ptr as *const u8; let read_slice = std::slice::from_raw_parts(byte_ptr, byte_len); - let bytes_to_extend = ptr.cursor + read_slice.len(); - if bytes_to_extend > ptr.backed.len() { - ptr.backed - .append(&mut vec![0; bytes_to_extend - ptr.backed.len()]); - } - let write_slice = &mut ptr.backed[ptr.cursor..(ptr.cursor + read_slice.len())]; - assert_eq!(write_slice.len(), read_slice.len()); - let written = read_slice.len(); - for (source, target) in read_slice.iter().zip(write_slice.iter_mut()) { - *target = *source; - } - written as i64 + ptr.backed.extend_from_slice(read_slice); + read_slice.len() as i64 } unsafe extern "C" fn wasi_console_out_seek_memory( @@ -506,7 +496,8 @@ pub unsafe extern "C" fn wasi_console_out_write_bytes( use std::io::Write; let buf = buf as *const u8; let ptr = &mut *ptr; - match ptr.write(std::slice::from_raw_parts(buf, len)) { + let read_slice = std::slice::from_raw_parts(buf, len); + match ptr.write(read_slice) { Ok(o) => o as i64, Err(_) => -1, } @@ -590,7 +581,7 @@ pub unsafe extern "C" fn wasi_console_out_read_str( target.push(0); let len = target.len(); - let c_string = match CString::from_vec_with_nul(target) { + let c_string = match CString::from_vec_with_nul(target.clone()) { Ok(o) => o, Err(_) => { return -1; @@ -852,15 +843,7 @@ pub unsafe extern "C" fn wasi_console_stdin_response_write_bytes( len: usize, ) -> i64 { let slice = std::slice::from_raw_parts(bytes, len); - let bytes_to_extend = response_t.response_data.len() as i64 - slice.len() as i64; - if bytes_to_extend > 0 { - response_t - .response_data - .append(&mut vec![0; bytes_to_extend as usize]); - } - for (source, target) in slice.iter().zip(response_t.response_data.iter_mut()) { - *target = *source; - } + response_t.response_data.extend_from_slice(slice); slice.len() as i64 } @@ -901,7 +884,6 @@ impl io::Read for wasi_console_stdin_t { &mut target, ) }; - if result >= 0 { for (source, target) in target.response_data.iter().zip(buf.iter_mut()) { *target = *source as u8; @@ -942,7 +924,7 @@ impl VirtualFile for wasi_console_stdin_t { 0 } fn size(&self) -> u64 { - u64::MAX + 0 } fn set_len(&mut self, _: u64) -> Result<(), FsError> { Ok(()) @@ -1328,14 +1310,14 @@ mod tests { #[test] fn test_wasi_stdin_set() { (assert_c! { - #include "../../lib/c-api/wasmer.h" + #include "tests/wasmer.h" #include "string.h" #include "stdio.h" - + typedef struct { - int u; + int invocation; } CustomWasiStdin; - + long CustomWasiStdin_destructor( const void* env, __u_long sz, @@ -1346,7 +1328,7 @@ mod tests { (void)ao; return 0; } - + long CustomWasiStdin_onStdIn( const void* env, __u_long sz, @@ -1354,43 +1336,28 @@ mod tests { __u_long maxwrite, wasi_console_stdin_response_t* in ) { - (void)env; + CustomWasiStdin* ptr = (CustomWasiStdin*)env; (void)sz; (void)ao; (void)maxwrite; - - wasi_console_stdin_response_write_str(in, "hello"); - return 5; + if (ptr->invocation == 0) { + wasi_console_stdin_response_write_str(in, "hello"); + ptr->invocation += 1; + return 5; // sizeof("hello") + } else { + return 0; + } } - + int main() { - + wasm_engine_t* engine = wasm_engine_new(); - if (!engine) { - printf("> Error loading engine!\n"); - return 1; - } wasm_store_t* store = wasm_store_new(engine); - if (!store) { - printf("> Error loading store!\n"); - return 1; - } wasi_config_t* config = wasi_config_new("example_program"); - if (!config) { - printf("> Error loading config!\n"); - return 1; - } wasi_console_out_t* override_stdout = wasi_console_out_new_memory(); - if (!override_stdout) { - printf("> Error loading override_stdout!\n"); - return 1; - } wasi_console_out_t* override_stderr = wasi_console_out_new_memory(); - if (!override_stderr) { - printf("> Error loading override_stderr!\n"); - return 1; - } - CustomWasiStdin stdin = { .u = 0 }; + + CustomWasiStdin stdin = { .invocation = 0 }; wasi_console_stdin_t* override_stdin = wasi_console_stdin_new( CustomWasiStdin_onStdIn, CustomWasiStdin_destructor, @@ -1398,77 +1365,75 @@ mod tests { sizeof(stdin), 8 // alignof(stdin) ); - + // Cloning the `wasi_console_out_t` does not deep-clone the // internal stream, since that is locked behind an Arc>. wasi_console_out_t* stdout_receiver = wasi_console_out_clone(override_stdout); wasi_console_out_t* stderr_receiver = wasi_console_out_clone(override_stderr); - + // The override_stdin ownership is moved to the config wasi_config_overwrite_stdin(config, override_stdin); wasi_config_overwrite_stdout(config, override_stdout); wasi_config_overwrite_stderr(config, override_stderr); - + // Load binary. - printf("Loading binary...\n"); FILE* file = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); if (!file) { printf("> Error loading module!\n"); return 1; } - + fseek(file, 0L, SEEK_END); size_t file_size = ftell(file); fseek(file, 0L, SEEK_SET); - + wasm_byte_vec_t binary; wasm_byte_vec_new_uninitialized(&binary, file_size); - + if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); return 1; } - + fclose(file); - - printf("Compiling module...\n"); + wasm_module_t* module = wasm_module_new(store, &binary); if (!module) { printf("> Error compiling module!\n"); return 1; } - + // The env now has ownership of the config (using the custom stdout / stdin channels) wasi_env_t *wasi_env = wasi_env_new(store, config); if (!wasi_env) { printf("> Error building WASI env!\n"); return 1; } - + wasm_importtype_vec_t import_types; wasm_module_imports(module, &import_types); - + wasm_extern_vec_t imports; wasm_extern_vec_new_uninitialized(&imports, import_types.size); wasm_importtype_vec_delete(&import_types); - + bool get_imports_result = wasi_get_imports(store, wasi_env, module, &imports); - + if (!get_imports_result) { - printf("Error getting WASI imports!\n"); - return 1; + printf("Error getting WASI imports!\n"); + return 1; } - + // The program should wait for a stdin, then print "stdout: $1" to stdout // and "stderr: $1" to stderr and exit. - + // Instantiate the module wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); return -1; } - + // Read the exports. wasm_extern_vec_t exports; wasm_instance_exports(instance, &exports); @@ -1479,20 +1444,20 @@ mod tests { break; } } - + if (!mem) { printf("Failed to create instance: Could not find memory in exports\n"); return -1; } wasi_env_set_memory(wasi_env, mem); - + // Get the _start function wasm_func_t* run_func = wasi_get_start_function(instance); if (run_func == NULL) { printf("> Error accessing export!\n"); return 1; } - + // Run the _start function // Running the program should trigger the stdin to write "hello" to the stdin wasm_val_vec_t args = WASM_EMPTY_VEC; @@ -1501,39 +1466,38 @@ mod tests { printf("> Error calling function!\n"); return 1; } - + // Verify that the stdout / stderr worked as expected char* out; wasi_console_out_read_str(stdout_receiver, &out); - printf("stdout 1: \"%s\"\n", out); assert(strcmp(out, "stdout: hello") == 0); wasi_console_out_delete_str(out); - - wasi_console_out_read_str(stdout_receiver, &out); - printf("stdout 2: \"%s\"\n", out); - assert(strcmp(out, "")); - wasi_console_out_delete_str(out); - - wasi_console_out_read_str(stderr_receiver, &out); - printf("stdout 3: \"%s\"\n", out); - assert(strcmp(out, "stderr: hello")); - wasi_console_out_delete_str(out); - - wasi_console_out_read_str(stderr_receiver, &out); - printf("stdout 4: \"%s\"\n", out); - assert(strcmp(out, "")); - wasi_console_out_delete_str(out); - + + char* out2; + wasi_console_out_read_str(stdout_receiver, &out2); + assert(strcmp(out2, "") == 0); + wasi_console_out_delete_str(out2); + + char* out3; + wasi_console_out_read_str(stderr_receiver, &out3); + assert(strcmp(out3, "stderr: hello") == 0); + wasi_console_out_delete_str(out3); + + char* out4; + wasi_console_out_read_str(stderr_receiver, &out4); + assert(strcmp(out4, "") == 0); + wasi_console_out_delete_str(out4); + wasi_console_out_delete(stdout_receiver); wasi_console_out_delete(stderr_receiver); - + wasm_byte_vec_delete(&binary); wasm_module_delete(module); wasm_func_delete(run_func); wasi_env_delete(wasi_env); wasm_store_delete(store); wasm_engine_delete(engine); - + return 0; } }) From ed4fb725488fa2f3c271b3db76b7b208423e3f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 2 Aug 2022 19:47:51 +0200 Subject: [PATCH 14/65] cargo fmt --- CHANGELOG.md | 1 + lib/c-api/src/wasm_c_api/wasi/mod.rs | 70 ++++++++++++++-------------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d57e4504490..8dae56f28e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C ## **Unreleased** ### Added +- [#3032](https://github.com/wasmerio/wasmer/pull/3032) Added C API for overwriting stdin / stdout I/O ### Changed - [#3075](https://github.com/wasmerio/wasmer/pull/3075) Remove __wbindgen_thread_id diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 142b27f4e7e..0f3153725d8 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -263,7 +263,9 @@ impl VirtualFile for wasi_console_out_t { 0 } fn size(&self) -> u64 { - self.get_data_mut("size").map(|s| s.len() as u64).unwrap_or(0) + self.get_data_mut("size") + .map(|s| s.len() as u64) + .unwrap_or(0) } fn set_len(&mut self, _: u64) -> Result<(), FsError> { Ok(()) @@ -1313,11 +1315,11 @@ mod tests { #include "tests/wasmer.h" #include "string.h" #include "stdio.h" - + typedef struct { int invocation; } CustomWasiStdin; - + long CustomWasiStdin_destructor( const void* env, __u_long sz, @@ -1328,7 +1330,7 @@ mod tests { (void)ao; return 0; } - + long CustomWasiStdin_onStdIn( const void* env, __u_long sz, @@ -1348,9 +1350,9 @@ mod tests { return 0; } } - + int main() { - + wasm_engine_t* engine = wasm_engine_new(); wasm_store_t* store = wasm_store_new(engine); wasi_config_t* config = wasi_config_new("example_program"); @@ -1365,75 +1367,75 @@ mod tests { sizeof(stdin), 8 // alignof(stdin) ); - + // Cloning the `wasi_console_out_t` does not deep-clone the // internal stream, since that is locked behind an Arc>. wasi_console_out_t* stdout_receiver = wasi_console_out_clone(override_stdout); wasi_console_out_t* stderr_receiver = wasi_console_out_clone(override_stderr); - + // The override_stdin ownership is moved to the config wasi_config_overwrite_stdin(config, override_stdin); wasi_config_overwrite_stdout(config, override_stdout); wasi_config_overwrite_stderr(config, override_stderr); - + // Load binary. FILE* file = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); if (!file) { printf("> Error loading module!\n"); return 1; } - + fseek(file, 0L, SEEK_END); size_t file_size = ftell(file); fseek(file, 0L, SEEK_SET); - + wasm_byte_vec_t binary; wasm_byte_vec_new_uninitialized(&binary, file_size); - + if (fread(binary.data, file_size, 1, file) != 1) { printf("> Error loading module!\n"); return 1; } - + fclose(file); - + wasm_module_t* module = wasm_module_new(store, &binary); if (!module) { printf("> Error compiling module!\n"); return 1; } - - // The env now has ownership of the config (using the custom stdout / stdin channels) + + // The env now has ownership of the config (using the custom stdout / stdin channels) wasi_env_t *wasi_env = wasi_env_new(store, config); if (!wasi_env) { printf("> Error building WASI env!\n"); return 1; } - + wasm_importtype_vec_t import_types; wasm_module_imports(module, &import_types); - + wasm_extern_vec_t imports; wasm_extern_vec_new_uninitialized(&imports, import_types.size); wasm_importtype_vec_delete(&import_types); - + bool get_imports_result = wasi_get_imports(store, wasi_env, module, &imports); - + if (!get_imports_result) { - printf("Error getting WASI imports!\n"); + printf("Error getting WASI imports!\n"); return 1; } - + // The program should wait for a stdin, then print "stdout: $1" to stdout // and "stderr: $1" to stderr and exit. - + // Instantiate the module wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); return -1; } - + // Read the exports. wasm_extern_vec_t exports; wasm_instance_exports(instance, &exports); @@ -1444,20 +1446,20 @@ mod tests { break; } } - + if (!mem) { printf("Failed to create instance: Could not find memory in exports\n"); return -1; } wasi_env_set_memory(wasi_env, mem); - + // Get the _start function wasm_func_t* run_func = wasi_get_start_function(instance); if (run_func == NULL) { printf("> Error accessing export!\n"); return 1; } - + // Run the _start function // Running the program should trigger the stdin to write "hello" to the stdin wasm_val_vec_t args = WASM_EMPTY_VEC; @@ -1466,38 +1468,38 @@ mod tests { printf("> Error calling function!\n"); return 1; } - + // Verify that the stdout / stderr worked as expected char* out; wasi_console_out_read_str(stdout_receiver, &out); assert(strcmp(out, "stdout: hello") == 0); wasi_console_out_delete_str(out); - + char* out2; wasi_console_out_read_str(stdout_receiver, &out2); assert(strcmp(out2, "") == 0); wasi_console_out_delete_str(out2); - + char* out3; wasi_console_out_read_str(stderr_receiver, &out3); assert(strcmp(out3, "stderr: hello") == 0); wasi_console_out_delete_str(out3); - + char* out4; wasi_console_out_read_str(stderr_receiver, &out4); assert(strcmp(out4, "") == 0); wasi_console_out_delete_str(out4); - + wasi_console_out_delete(stdout_receiver); wasi_console_out_delete(stderr_receiver); - + wasm_byte_vec_delete(&binary); wasm_module_delete(module); wasm_func_delete(run_func); wasi_env_delete(wasi_env); wasm_store_delete(store); wasm_engine_delete(engine); - + return 0; } }) From aa27a66fc4a74b7e993f2416ac6c257577d8efe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 2 Aug 2022 21:57:49 +0200 Subject: [PATCH 15/65] Fix __u_long to size_t in C API --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 0f3153725d8..4661c0b1bc3 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -1322,8 +1322,8 @@ mod tests { long CustomWasiStdin_destructor( const void* env, - __u_long sz, - __u_long ao + size_t sz, + size_t ao ) { (void)env; (void)sz; @@ -1333,9 +1333,9 @@ mod tests { long CustomWasiStdin_onStdIn( const void* env, - __u_long sz, - __u_long ao, - __u_long maxwrite, + size_t sz, + size_t ao, + size_t maxwrite, wasi_console_stdin_response_t* in ) { CustomWasiStdin* ptr = (CustomWasiStdin*)env; From 2ff8d3431b38af183c8bd59f03bbf4a28e86a76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Wed, 3 Aug 2022 10:35:43 +0200 Subject: [PATCH 16/65] Change size_t to unsigned long --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 4661c0b1bc3..ba3215f99f3 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -1322,8 +1322,8 @@ mod tests { long CustomWasiStdin_destructor( const void* env, - size_t sz, - size_t ao + unsigned long sz, + unsigned long ao ) { (void)env; (void)sz; @@ -1333,9 +1333,9 @@ mod tests { long CustomWasiStdin_onStdIn( const void* env, - size_t sz, - size_t ao, - size_t maxwrite, + unsigned long sz, + unsigned long ao, + unsigned long maxwrite, wasi_console_stdin_response_t* in ) { CustomWasiStdin* ptr = (CustomWasiStdin*)env; From 12247004fefe7d9c62f50c7c036b7d37e6bee195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 5 Aug 2022 09:45:18 +0200 Subject: [PATCH 17/65] Use int64_t / uintptr_t --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index ba3215f99f3..fe30b6e8916 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -1320,10 +1320,10 @@ mod tests { int invocation; } CustomWasiStdin; - long CustomWasiStdin_destructor( + int64_t CustomWasiStdin_destructor( const void* env, - unsigned long sz, - unsigned long ao + uintptr_t sz, + uintptr_t ao ) { (void)env; (void)sz; @@ -1331,11 +1331,11 @@ mod tests { return 0; } - long CustomWasiStdin_onStdIn( + int64_t CustomWasiStdin_onStdIn( const void* env, - unsigned long sz, - unsigned long ao, - unsigned long maxwrite, + uintptr_t sz, + uintptr_t ao, + uintptr_t maxwrite, wasi_console_stdin_response_t* in ) { CustomWasiStdin* ptr = (CustomWasiStdin*)env; From f1a33505bb140ce0faddbc63c1bc7a8ccab863d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 5 Aug 2022 10:43:32 +0200 Subject: [PATCH 18/65] cargo update --- Cargo.lock | 117 +++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dddf556ddd3..093318c95fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" +checksum = "c91f1f46651137be86f3a2b9a8359f9ab421d04d941c62b5982e1ca21113adf9" [[package]] name = "arbitrary" @@ -242,9 +242,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "bytesize" @@ -264,7 +264,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" dependencies = [ - "clap 3.2.15", + "clap 3.2.16", "heck 0.4.0", "indexmap", "log", @@ -345,9 +345,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.15" +version = "3.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bbe24bbd31a185bc2c4f7c2abe80bea13a20d57ee4e55be70ac512bdc76417" +checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9" dependencies = [ "atty", "bitflags", @@ -890,9 +890,9 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d013529d5574a60caeda29e179e695125448e5de52e3874f7b4c1d7360e18e" +checksum = "003000e712ad0f95857bd4d2ef8d1890069e06554101697d12050668b2f6f020" dependencies = [ "serde", ] @@ -980,9 +980,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -1012,9 +1012,9 @@ dependencies = [ [[package]] name = "ghost" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93490550b1782c589a350f2211fff2e34682e25fed17ef53fc4fa8fe184975e" +checksum = "eb19fe8de3ea0920d282f7b77dd4227aea6b8b999b42cdf0ca41b2472b14443a" dependencies = [ "proc-macro2", "quote", @@ -1225,9 +1225,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "js-sys" @@ -1258,9 +1258,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" [[package]] name = "libfuzzer-sys" @@ -1564,9 +1564,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22" [[package]] name = "peeking_take_while" @@ -1576,10 +1576,11 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pest" -version = "2.1.3" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "69486e2b8c2d2aeb9762db7b4e00b0331156393555cff467f4163ff06821eef8" dependencies = [ + "thiserror", "ucd-trie", ] @@ -1713,9 +1714,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -1742,9 +1743,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -1850,9 +1851,9 @@ checksum = "a0d51660a68078997855ba5602f73ab3a5031bd7ad480a9d4c90fbbf04e1fff0" [[package]] name = "regalloc2" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ff2e57a7d050308b3fde0f707aa240b491b190e3855f212860f11bb3af4205" +checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779" dependencies = [ "fxhash", "log", @@ -1978,7 +1979,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.12", + "semver 1.0.13", ] [[package]] @@ -1995,15 +1996,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "same-file" @@ -2077,9 +2078,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" [[package]] name = "semver-parser" @@ -2098,18 +2099,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.140" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" dependencies = [ "serde", ] @@ -2126,9 +2127,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.140" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" dependencies = [ "proc-macro2", "quote", @@ -2137,11 +2138,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" dependencies = [ - "itoa 1.0.2", + "itoa 1.0.3", "ryu", "serde", ] @@ -2327,9 +2328,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -2437,18 +2438,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" dependencies = [ "proc-macro2", "quote", @@ -2523,9 +2524,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if 1.0.0", "log", @@ -2547,9 +2548,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ "once_cell", ] @@ -2582,9 +2583,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "764b9e244b482a9b81bde596aa37aa6f1347bf8007adab25e59f901b32b4e0a0" +checksum = "e7f408301c7480f9e6294eb779cfc907f54bd901a9660ef24d7f233ed5376485" dependencies = [ "glob", "once_cell", @@ -2633,9 +2634,9 @@ checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" [[package]] name = "unicode-ident" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "unicode-segmentation" @@ -3025,7 +3026,7 @@ dependencies = [ "rayon", "regex", "rustc_version 0.4.0", - "semver 1.0.12", + "semver 1.0.13", "smallvec", "target-lexicon 0.12.4", "wasmer-compiler", From ac127d8d36bae08baf4b27148d2a98add1bec8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 5 Aug 2022 12:41:37 +0200 Subject: [PATCH 19/65] Fix clippy errors in lib/c-api/src/wasm_c_api/wasi/mod.rs --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index fe30b6e8916..9c2289009f3 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -146,7 +146,7 @@ impl fmt::Debug for wasi_console_out_t { impl io::Read for wasi_console_out_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { - let self_read = self.read.clone(); + let self_read = self.read; let self_align = self.align; let mut data = self.get_data_mut("read")?; let result = unsafe { @@ -171,7 +171,7 @@ impl io::Read for wasi_console_out_t { impl io::Write for wasi_console_out_t { fn write(&mut self, buf: &[u8]) -> io::Result { - let self_write = self.write.clone(); + let self_write = self.write; let self_align = self.align; let mut data = self.get_data_mut("write")?; let result = unsafe { @@ -197,7 +197,7 @@ impl io::Write for wasi_console_out_t { } } fn flush(&mut self) -> io::Result<()> { - let self_write = self.write.clone(); + let self_write = self.write; let self_align = self.align; let mut data = self.get_data_mut("flush")?; let bytes_to_write = &[]; @@ -224,7 +224,7 @@ impl io::Write for wasi_console_out_t { impl io::Seek for wasi_console_out_t { fn seek(&mut self, pos: SeekFrom) -> io::Result { - let self_seek = self.seek.clone(); + let self_seek = self.seek; let self_align = self.align; let mut data = self.get_data_mut("seek")?; let (id, pos) = match pos { @@ -769,6 +769,7 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { config.inherit_stdin = None; } +#[allow(clippy::box_collection, clippy::redundant_allocation)] #[repr(C)] pub struct wasi_console_stdin_t { on_stdin: WasiConsoleIoOnStdinCallback, @@ -779,7 +780,7 @@ pub struct wasi_console_stdin_t { impl wasi_console_stdin_t { fn get_data_mut(&mut self, op_id: &'static str) -> io::Result<&mut Vec> { - self.data.as_mut().map(|s| &mut (**s)).ok_or({ + self.data.as_deref_mut().ok_or_else(|| { io::Error::new( io::ErrorKind::Other, format!("could not get env data ({op_id}) on wasi_console_stdin_t"), @@ -831,6 +832,7 @@ pub unsafe extern "C" fn wasi_console_stdin_delete(ptr: *mut wasi_console_stdin_ true } +#[allow(clippy::box_collection, clippy::redundant_allocation)] #[derive(Clone)] #[repr(C)] pub struct wasi_console_stdin_response_t { From 838d932bd39057003a05e02cc0af49d4c660ea1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Wed, 17 Aug 2022 18:24:52 +0200 Subject: [PATCH 20/65] Use wasi::Pipe --- Cargo.lock | 2 +- lib/c-api/src/wasm_c_api/wasi/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e1eb8b935f..9328944bd83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -271,7 +271,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" dependencies = [ "clap 3.2.16", - "heck 0.4.0", + "heck", "indexmap", "log", "proc-macro2", diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 9c2289009f3..9f0df00c4ea 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -24,7 +24,7 @@ use std::{ }; use wasmer_wasi::{ get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiState, WasiStateBuilder, - WasiVersion, + WasiVersion, Pipe, }; /// Function callback that takes: From df0567900ca09f09527833c7a0bf7352bc295c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Wed, 17 Aug 2022 18:50:27 +0200 Subject: [PATCH 21/65] First work to translate from WasiConsoleMemoryOverride to Pipe --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 80 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 9f0df00c4ea..2bc8565948e 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -347,26 +347,21 @@ extern "C" fn wasi_console_out_delete_null(_: *const c_void, _: usize, _: usize) 0 } -#[derive(Default)] -struct WasiConsoleMemoryOverride { - backed: Vec, - cursor: usize, -} - unsafe extern "C" fn wasi_console_out_read_memory( - ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ - sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ - alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + ptr: *const c_void, /* = *Pipe */ + sizeof: usize, /* = sizeof(Pipe) */ + alignof: usize, /* = alignof(Pipe) */ byte_ptr: *mut c_char, /* &[u8] bytes to read */ max_bytes: usize, /* max bytes to read */ ) -> i64 { - if sizeof != std::mem::size_of::() - || alignof != std::mem::align_of::() + if sizeof != std::mem::size_of::() + || alignof != std::mem::align_of::() { return -1; } - let ptr = ptr as *mut WasiConsoleMemoryOverride; + let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; + /* let read_slice = &ptr.backed[ptr.cursor..]; let byte_ptr = byte_ptr as *mut u8; let write_slice = std::slice::from_raw_parts_mut(byte_ptr, max_bytes); @@ -376,88 +371,95 @@ unsafe extern "C" fn wasi_console_out_read_memory( } ptr.cursor += read; read as i64 + */ } unsafe extern "C" fn wasi_console_out_write_memory( - ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ - sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ - alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + ptr: *const c_void, /* = *Pipe */ + sizeof: usize, /* = sizeof(Pipe) */ + alignof: usize, /* = alignof(Pipe) */ byte_ptr: *const c_char, byte_len: usize, flush: bool, ) -> i64 { - if sizeof != std::mem::size_of::() - || alignof != std::mem::align_of::() + if sizeof != std::mem::size_of::() + || alignof != std::mem::align_of::() { return -1; } + let ptr = ptr as *mut Pipe; + let ptr = &mut *ptr; + + /* if flush { return 0; } - let ptr = ptr as *mut WasiConsoleMemoryOverride; - let ptr = &mut *ptr; let byte_ptr = byte_ptr as *const u8; let read_slice = std::slice::from_raw_parts(byte_ptr, byte_len); ptr.backed.extend_from_slice(read_slice); read_slice.len() as i64 + */ } unsafe extern "C" fn wasi_console_out_seek_memory( - ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ - sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ - alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + ptr: *const c_void, /* = *Pipe */ + sizeof: usize, /* = sizeof(Pipe) */ + alignof: usize, /* = alignof(Pipe) */ direction: c_char, seek_to: i64, ) -> i64 { - if sizeof != std::mem::size_of::() - || alignof != std::mem::align_of::() + if sizeof != std::mem::size_of::() + || alignof != std::mem::align_of::() { return -1; } - let ptr = ptr as *mut WasiConsoleMemoryOverride; + let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; if direction == 0 { + /* // seek from start let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); let diff = ptr.cursor as i64 - seek_to as i64; ptr.cursor = seek_to; - diff + diff*/ } else if direction == 1 { + /* // seek from end let seek_to = ptr.backed.len() as i64 + seek_to; let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); let diff = ptr.cursor as i64 - seek_to as i64; ptr.cursor = seek_to; - diff + diff*/ } else if direction == 2 { // seek from cursor + /* let seek_to = ptr.cursor as i64 + seek_to; let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); let diff = ptr.cursor as i64 - seek_to as i64; ptr.cursor = seek_to; diff + */ } else { -1 } } unsafe extern "C" fn wasi_console_out_delete_memory( - ptr: *const c_void, /* = *WasiConsoleMemoryOverride */ - sizeof: usize, /* = sizeof(WasiConsoleMemoryOverride) */ - alignof: usize, /* = alignof(WasiConsoleMemoryOverride) */ + ptr: *const c_void, /* = *Pipe */ + sizeof: usize, /* = sizeof(Pipe) */ + alignof: usize, /* = alignof(Pipe) */ ) -> i64 { - if sizeof != std::mem::size_of::() - || alignof != std::mem::align_of::() + if sizeof != std::mem::size_of::() + || alignof != std::mem::align_of::() { return -1; } - let ptr = ptr as *mut WasiConsoleMemoryOverride; + let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; - ptr.backed = Vec::new(); - ptr.cursor = 0; + let _ = Box::from_raw(ptr); // TODO: correct? // dropped here, destructors run here 0 } @@ -468,9 +470,9 @@ unsafe extern "C" fn wasi_console_out_delete_memory( pub unsafe extern "C" fn wasi_console_out_new_memory() -> *mut wasi_console_out_t { use std::mem::ManuallyDrop; - let data = WasiConsoleMemoryOverride::default(); + let data = Pipe::new(); let mut data = ManuallyDrop::new(data); - let ptr: &mut WasiConsoleMemoryOverride = &mut data; + let ptr: &mut Pipe = &mut data; wasi_console_out_new( wasi_console_out_read_memory, @@ -478,8 +480,8 @@ pub unsafe extern "C" fn wasi_console_out_new_memory() -> *mut wasi_console_out_ wasi_console_out_seek_memory, wasi_console_out_delete_memory, ptr as *mut _ as *mut i8, - std::mem::size_of::(), - std::mem::align_of::(), + std::mem::size_of::(), + std::mem::align_of::(), ) } From 662be61c1508923c62f73f12193e8f915edb04e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Thu, 18 Aug 2022 10:48:41 +0200 Subject: [PATCH 22/65] Implement console_io_memory using wasi::Pipe --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 74 +++++++++++----------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 2bc8565948e..091e63a1a03 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -354,6 +354,7 @@ unsafe extern "C" fn wasi_console_out_read_memory( byte_ptr: *mut c_char, /* &[u8] bytes to read */ max_bytes: usize, /* max bytes to read */ ) -> i64 { + use std::io::Read; if sizeof != std::mem::size_of::() || alignof != std::mem::align_of::() { @@ -361,17 +362,11 @@ unsafe extern "C" fn wasi_console_out_read_memory( } let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; - /* - let read_slice = &ptr.backed[ptr.cursor..]; - let byte_ptr = byte_ptr as *mut u8; - let write_slice = std::slice::from_raw_parts_mut(byte_ptr, max_bytes); - let read = read_slice.len().min(write_slice.len()); - for (source, target) in read_slice.iter().zip(write_slice.iter_mut()) { - *target = *source; + let slice = std::slice::from_raw_parts_mut(byte_ptr as *mut u8, max_bytes); + match ptr.read(slice) { + Ok(o) => o as i64, + Err(_) => -1, } - ptr.cursor += read; - read as i64 - */ } unsafe extern "C" fn wasi_console_out_write_memory( @@ -382,25 +377,28 @@ unsafe extern "C" fn wasi_console_out_write_memory( byte_len: usize, flush: bool, ) -> i64 { + use std::io::Write; if sizeof != std::mem::size_of::() || alignof != std::mem::align_of::() { return -1; } - + let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; - /* if flush { - return 0; + match ptr.flush() { + Ok(()) => 0, + Err(_) => -1, + } + } else { + let slice = std::slice::from_raw_parts(byte_ptr as *const u8, byte_len); + match ptr.write(slice) { + Ok(o) => o as i64, + Err(_) => -1, + } } - - let byte_ptr = byte_ptr as *const u8; - let read_slice = std::slice::from_raw_parts(byte_ptr, byte_len); - ptr.backed.extend_from_slice(read_slice); - read_slice.len() as i64 - */ } unsafe extern "C" fn wasi_console_out_seek_memory( @@ -410,40 +408,26 @@ unsafe extern "C" fn wasi_console_out_seek_memory( direction: c_char, seek_to: i64, ) -> i64 { + use std::io::Seek; if sizeof != std::mem::size_of::() || alignof != std::mem::align_of::() { return -1; } + let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; - if direction == 0 { - /* - // seek from start - let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); - let diff = ptr.cursor as i64 - seek_to as i64; - ptr.cursor = seek_to; - diff*/ - } else if direction == 1 { - /* - // seek from end - let seek_to = ptr.backed.len() as i64 + seek_to; - let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); - let diff = ptr.cursor as i64 - seek_to as i64; - ptr.cursor = seek_to; - diff*/ - } else if direction == 2 { - // seek from cursor - /* - let seek_to = ptr.cursor as i64 + seek_to; - let seek_to = (seek_to.max(0_i64) as usize).min(ptr.backed.len()); - let diff = ptr.cursor as i64 - seek_to as i64; - ptr.cursor = seek_to; - diff - */ - } else { - -1 + let seek_from = match direction { + 0 => std::io::SeekFrom::Start(seek_to.max(0) as u64), + 1 => std::io::SeekFrom::End(seek_to), + 2 => std::io::SeekFrom::Current(seek_to), + _ => { return -1; }, + }; + + match ptr.seek(seek_from) { + Ok(o) => o as i64, + Err(_) => -1, } } From 16f7ff7cf03bd7ba7931e338bdf18f5d54ac6935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Thu, 18 Aug 2022 18:13:07 +0200 Subject: [PATCH 23/65] Address review changes --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 89 ++++------------------------ 1 file changed, 12 insertions(+), 77 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 091e63a1a03..a24379042e1 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -34,12 +34,12 @@ use wasmer_wasi::{ /// - a *const to the bytes to write /// - the length of the bytes to write pub type WasiConsoleIoReadCallback = - unsafe extern "C" fn(*const c_void, usize, usize, *mut c_char, usize) -> i64; + unsafe extern "C" fn(*const c_void, *mut c_char, usize) -> i64; pub type WasiConsoleIoWriteCallback = - unsafe extern "C" fn(*const c_void, usize, usize, *const c_char, usize, bool) -> i64; + unsafe extern "C" fn(*const c_void, *const c_char, usize, bool) -> i64; pub type WasiConsoleIoSeekCallback = - unsafe extern "C" fn(*const c_void, usize, usize, c_char, i64) -> i64; -pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void, usize, usize) -> i64; + unsafe extern "C" fn(*const c_void, c_char, i64) -> i64; +pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void) -> i64; /// Callback that is activated whenever the program wants to read from stdin /// /// Parameters: @@ -56,8 +56,6 @@ pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void, usize, pub type WasiConsoleIoOnStdinCallback = unsafe extern "C" fn( *const c_void, usize, - usize, - usize, *mut wasi_console_stdin_response_t, ) -> i64; @@ -78,7 +76,6 @@ pub struct wasi_console_out_t { seek: WasiConsoleIoSeekCallback, destructor: WasiConsoleIoEnvDestructor, data: Option>>>>, - align: usize, } impl wasi_console_out_t { @@ -103,7 +100,6 @@ impl wasi_console_out_t { impl Drop for wasi_console_out_t { fn drop(&mut self) { - let align = self.align; let data = match self.data.take() { Some(s) => s, None => { @@ -127,9 +123,7 @@ impl Drop for wasi_console_out_t { let error = unsafe { (self.destructor)( - inner_value.as_mut_ptr() as *const c_void, - inner_value.len(), - align, + inner_value.as_mut_ptr() as *const c_void ) }; if error < 0 { @@ -147,13 +141,10 @@ impl fmt::Debug for wasi_console_out_t { impl io::Read for wasi_console_out_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { let self_read = self.read; - let self_align = self.align; let mut data = self.get_data_mut("read")?; let result = unsafe { (self_read)( data.as_mut_ptr() as *const c_void, - data.len(), - self_align, buf.as_mut_ptr() as *mut c_char, buf.len(), ) @@ -172,13 +163,10 @@ impl io::Read for wasi_console_out_t { impl io::Write for wasi_console_out_t { fn write(&mut self, buf: &[u8]) -> io::Result { let self_write = self.write; - let self_align = self.align; let mut data = self.get_data_mut("write")?; let result = unsafe { (self_write)( data.as_mut_ptr() as *const c_void, - data.len(), - self_align, buf.as_ptr() as *const c_char, buf.len(), false, @@ -198,14 +186,11 @@ impl io::Write for wasi_console_out_t { } fn flush(&mut self) -> io::Result<()> { let self_write = self.write; - let self_align = self.align; let mut data = self.get_data_mut("flush")?; let bytes_to_write = &[]; let result: i64 = unsafe { (self_write)( data.as_mut_ptr() as *const c_void, - data.len(), - self_align, bytes_to_write.as_ptr(), 0, true, @@ -225,7 +210,6 @@ impl io::Write for wasi_console_out_t { impl io::Seek for wasi_console_out_t { fn seek(&mut self, pos: SeekFrom) -> io::Result { let self_seek = self.seek; - let self_align = self.align; let mut data = self.get_data_mut("seek")?; let (id, pos) = match pos { SeekFrom::Start(s) => (0, s as i64), @@ -235,8 +219,6 @@ impl io::Seek for wasi_console_out_t { let result = unsafe { (self_seek)( data.as_mut_ptr() as *const c_void, - data.len(), - self_align, id, pos, ) @@ -282,11 +264,10 @@ pub unsafe extern "C" fn wasi_console_out_new( write: WasiConsoleIoWriteCallback, seek: WasiConsoleIoSeekCallback, destructor: WasiConsoleIoEnvDestructor, - env_data: *const c_char, + env_data: *const c_void, env_data_len: usize, - env_data_align: usize, ) -> *mut wasi_console_out_t { - let data_vec: Vec = std::slice::from_raw_parts(env_data, env_data_len).to_vec(); + let data_vec: Vec = std::slice::from_raw_parts(env_data as *const c_char, env_data_len).to_vec(); Box::leak(Box::new(wasi_console_out_t { read, @@ -294,7 +275,6 @@ pub unsafe extern "C" fn wasi_console_out_new( seek, destructor, data: Some(Box::new(Arc::new(Mutex::new(data_vec)))), - align: env_data_align, })) } @@ -310,14 +290,11 @@ pub unsafe extern "C" fn wasi_console_out_new_null() -> *mut wasi_console_out_t wasi_console_out_delete_null, data.as_mut_ptr(), data.len(), - std::mem::align_of_val(&data), ) } extern "C" fn wasi_console_out_read_null( _: *const c_void, - _: usize, - _: usize, _: *mut c_char, _: usize, ) -> i64 { @@ -325,8 +302,6 @@ extern "C" fn wasi_console_out_read_null( } extern "C" fn wasi_console_out_write_null( _: *const c_void, - _: usize, - _: usize, _: *const c_char, _: usize, _: bool, @@ -335,31 +310,22 @@ extern "C" fn wasi_console_out_write_null( } extern "C" fn wasi_console_out_seek_null( _: *const c_void, - _: usize, - _: usize, _: c_char, _: i64, ) -> i64 { 0 } -extern "C" fn wasi_console_out_delete_null(_: *const c_void, _: usize, _: usize) -> i64 { +extern "C" fn wasi_console_out_delete_null(_: *const c_void) -> i64 { 0 } unsafe extern "C" fn wasi_console_out_read_memory( ptr: *const c_void, /* = *Pipe */ - sizeof: usize, /* = sizeof(Pipe) */ - alignof: usize, /* = alignof(Pipe) */ byte_ptr: *mut c_char, /* &[u8] bytes to read */ max_bytes: usize, /* max bytes to read */ ) -> i64 { use std::io::Read; - if sizeof != std::mem::size_of::() - || alignof != std::mem::align_of::() - { - return -1; - } let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; let slice = std::slice::from_raw_parts_mut(byte_ptr as *mut u8, max_bytes); @@ -371,18 +337,11 @@ unsafe extern "C" fn wasi_console_out_read_memory( unsafe extern "C" fn wasi_console_out_write_memory( ptr: *const c_void, /* = *Pipe */ - sizeof: usize, /* = sizeof(Pipe) */ - alignof: usize, /* = alignof(Pipe) */ byte_ptr: *const c_char, byte_len: usize, flush: bool, ) -> i64 { use std::io::Write; - if sizeof != std::mem::size_of::() - || alignof != std::mem::align_of::() - { - return -1; - } let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; @@ -403,17 +362,10 @@ unsafe extern "C" fn wasi_console_out_write_memory( unsafe extern "C" fn wasi_console_out_seek_memory( ptr: *const c_void, /* = *Pipe */ - sizeof: usize, /* = sizeof(Pipe) */ - alignof: usize, /* = alignof(Pipe) */ direction: c_char, seek_to: i64, ) -> i64 { use std::io::Seek; - if sizeof != std::mem::size_of::() - || alignof != std::mem::align_of::() - { - return -1; - } let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; @@ -433,14 +385,7 @@ unsafe extern "C" fn wasi_console_out_seek_memory( unsafe extern "C" fn wasi_console_out_delete_memory( ptr: *const c_void, /* = *Pipe */ - sizeof: usize, /* = sizeof(Pipe) */ - alignof: usize, /* = alignof(Pipe) */ ) -> i64 { - if sizeof != std::mem::size_of::() - || alignof != std::mem::align_of::() - { - return -1; - } let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; let _ = Box::from_raw(ptr); // TODO: correct? @@ -452,20 +397,17 @@ unsafe extern "C" fn wasi_console_out_delete_memory( /// for backing stdin / stdout / stderr #[no_mangle] pub unsafe extern "C" fn wasi_console_out_new_memory() -> *mut wasi_console_out_t { - use std::mem::ManuallyDrop; - let data = Pipe::new(); - let mut data = ManuallyDrop::new(data); - let ptr: &mut Pipe = &mut data; + let data = Box::new(Pipe::new()); + let ptr = Box::leak(data); wasi_console_out_new( wasi_console_out_read_memory, wasi_console_out_write_memory, wasi_console_out_seek_memory, wasi_console_out_delete_memory, - ptr as *mut _ as *mut i8, + ptr as *mut _ as *mut c_void, std::mem::size_of::(), - std::mem::align_of::(), ) } @@ -761,7 +703,6 @@ pub struct wasi_console_stdin_t { on_stdin: WasiConsoleIoOnStdinCallback, destructor: WasiConsoleIoEnvDestructor, data: Option>>, - align: usize, } impl wasi_console_stdin_t { @@ -781,20 +722,17 @@ pub unsafe extern "C" fn wasi_console_stdin_new( destructor: WasiConsoleIoEnvDestructor, ptr: *const c_void, len: usize, - align: usize, ) -> *mut wasi_console_stdin_t { let data = std::slice::from_raw_parts(ptr as *const c_char, len); Box::leak(Box::new(wasi_console_stdin_t { on_stdin, destructor, data: Some(Box::new(data.to_vec())), - align, })) } impl Drop for wasi_console_stdin_t { fn drop(&mut self) { - let align = self.align; let mut data = match self.data.take() { Some(s) => s, None => { @@ -803,7 +741,7 @@ impl Drop for wasi_console_stdin_t { }; let error = unsafe { - (self.destructor)((*data).as_mut_ptr() as *const c_void, (*data).len(), align) + (self.destructor)((*data).as_mut_ptr() as *const c_void) }; if error < 0 { @@ -862,14 +800,11 @@ impl io::Read for wasi_console_stdin_t { let mut target = wasi_console_stdin_response_t { response_data: Box::new(Vec::new()), }; - let self_align = self.align; let self_on_stdin = self.on_stdin; let data = self.get_data_mut("read")?; let result = unsafe { (self_on_stdin)( data.as_ptr() as *const c_void, - data.len(), - self_align, buf.len(), &mut target, ) From b7f30c99c3925a3deb073c93fe5215a36431be31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Thu, 18 Aug 2022 18:30:57 +0200 Subject: [PATCH 24/65] Fix errors in make test-capi --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index a24379042e1..9500d39f1e0 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -386,10 +386,8 @@ unsafe extern "C" fn wasi_console_out_seek_memory( unsafe extern "C" fn wasi_console_out_delete_memory( ptr: *const c_void, /* = *Pipe */ ) -> i64 { - let ptr = ptr as *mut Pipe; - let ptr = &mut *ptr; - let _ = Box::from_raw(ptr); // TODO: correct? - // dropped here, destructors run here + let ptr = ptr as *const Pipe; + let _: Pipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here 0 } @@ -397,9 +395,12 @@ unsafe extern "C" fn wasi_console_out_delete_memory( /// for backing stdin / stdout / stderr #[no_mangle] pub unsafe extern "C" fn wasi_console_out_new_memory() -> *mut wasi_console_out_t { + + use std::mem::ManuallyDrop; - let data = Box::new(Pipe::new()); - let ptr = Box::leak(data); + let data = Pipe::new(); + let mut data = ManuallyDrop::new(data); + let ptr: &mut Pipe = &mut data; wasi_console_out_new( wasi_console_out_read_memory, @@ -1244,26 +1245,18 @@ mod tests { } CustomWasiStdin; int64_t CustomWasiStdin_destructor( - const void* env, - uintptr_t sz, - uintptr_t ao + const void* env ) { (void)env; - (void)sz; - (void)ao; return 0; } int64_t CustomWasiStdin_onStdIn( const void* env, - uintptr_t sz, - uintptr_t ao, uintptr_t maxwrite, wasi_console_stdin_response_t* in ) { CustomWasiStdin* ptr = (CustomWasiStdin*)env; - (void)sz; - (void)ao; (void)maxwrite; if (ptr->invocation == 0) { wasi_console_stdin_response_write_str(in, "hello"); @@ -1287,8 +1280,7 @@ mod tests { CustomWasiStdin_onStdIn, CustomWasiStdin_destructor, &stdin, - sizeof(stdin), - 8 // alignof(stdin) + sizeof(stdin) ); // Cloning the `wasi_console_out_t` does not deep-clone the From 6e944fa65348cdb6846bbe557a467e38fc77943a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Thu, 18 Aug 2022 18:39:41 +0200 Subject: [PATCH 25/65] cargo fmt && make lint --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 71 ++++++++-------------------- 1 file changed, 21 insertions(+), 50 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 9500d39f1e0..7acb3c7fe9c 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -23,8 +23,8 @@ use std::{ sync::MutexGuard, }; use wasmer_wasi::{ - get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiState, WasiStateBuilder, - WasiVersion, Pipe, + get_wasi_version, FsError, Pipe, VirtualFile, WasiFile, WasiFunctionEnv, WasiState, + WasiStateBuilder, WasiVersion, }; /// Function callback that takes: @@ -33,12 +33,10 @@ use wasmer_wasi::{ /// - the length of the environment data /// - a *const to the bytes to write /// - the length of the bytes to write -pub type WasiConsoleIoReadCallback = - unsafe extern "C" fn(*const c_void, *mut c_char, usize) -> i64; +pub type WasiConsoleIoReadCallback = unsafe extern "C" fn(*const c_void, *mut c_char, usize) -> i64; pub type WasiConsoleIoWriteCallback = unsafe extern "C" fn(*const c_void, *const c_char, usize, bool) -> i64; -pub type WasiConsoleIoSeekCallback = - unsafe extern "C" fn(*const c_void, c_char, i64) -> i64; +pub type WasiConsoleIoSeekCallback = unsafe extern "C" fn(*const c_void, c_char, i64) -> i64; pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void) -> i64; /// Callback that is activated whenever the program wants to read from stdin /// @@ -53,11 +51,8 @@ pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void) -> i64 /// key event from the console I/O. With the custom environment pointer (the first argument) /// you can clone references to the stdout channel and - for example - inspect the stdout /// channel to answer depending on runtime-dependent stdout data. -pub type WasiConsoleIoOnStdinCallback = unsafe extern "C" fn( - *const c_void, - usize, - *mut wasi_console_stdin_response_t, -) -> i64; +pub type WasiConsoleIoOnStdinCallback = + unsafe extern "C" fn(*const c_void, usize, *mut wasi_console_stdin_response_t) -> i64; /// The console override is a custom context consisting of callback pointers /// (which are activated whenever some console I/O occurs) and a "context", which @@ -68,6 +63,7 @@ pub type WasiConsoleIoOnStdinCallback = unsafe extern "C" fn( /// Internally the stdout / stdin is synchronized, so the console is usable across threads /// (only one thread can read / write / seek from the console I/O) #[allow(non_camel_case_types)] +#[allow(clippy::box_collection, clippy::redundant_allocation)] #[repr(C)] #[derive(Clone)] pub struct wasi_console_out_t { @@ -121,11 +117,7 @@ impl Drop for wasi_console_out_t { } }; - let error = unsafe { - (self.destructor)( - inner_value.as_mut_ptr() as *const c_void - ) - }; + let error = unsafe { (self.destructor)(inner_value.as_mut_ptr() as *const c_void) }; if error < 0 { println!("error dropping wasi_console_out_t: {error}"); } @@ -216,13 +208,7 @@ impl io::Seek for wasi_console_out_t { SeekFrom::End(s) => (1, s), SeekFrom::Current(s) => (2, s), }; - let result = unsafe { - (self_seek)( - data.as_mut_ptr() as *const c_void, - id, - pos, - ) - }; + let result = unsafe { (self_seek)(data.as_mut_ptr() as *const c_void, id, pos) }; if result >= 0 { Ok(result.try_into().unwrap_or(0)) } else { @@ -267,7 +253,8 @@ pub unsafe extern "C" fn wasi_console_out_new( env_data: *const c_void, env_data_len: usize, ) -> *mut wasi_console_out_t { - let data_vec: Vec = std::slice::from_raw_parts(env_data as *const c_char, env_data_len).to_vec(); + let data_vec: Vec = + std::slice::from_raw_parts(env_data as *const c_char, env_data_len).to_vec(); Box::leak(Box::new(wasi_console_out_t { read, @@ -293,11 +280,7 @@ pub unsafe extern "C" fn wasi_console_out_new_null() -> *mut wasi_console_out_t ) } -extern "C" fn wasi_console_out_read_null( - _: *const c_void, - _: *mut c_char, - _: usize, -) -> i64 { +extern "C" fn wasi_console_out_read_null(_: *const c_void, _: *mut c_char, _: usize) -> i64 { 0 } extern "C" fn wasi_console_out_write_null( @@ -308,11 +291,7 @@ extern "C" fn wasi_console_out_write_null( ) -> i64 { 0 } -extern "C" fn wasi_console_out_seek_null( - _: *const c_void, - _: c_char, - _: i64, -) -> i64 { +extern "C" fn wasi_console_out_seek_null(_: *const c_void, _: c_char, _: i64) -> i64 { 0 } @@ -342,7 +321,7 @@ unsafe extern "C" fn wasi_console_out_write_memory( flush: bool, ) -> i64 { use std::io::Write; - + let ptr = ptr as *mut Pipe; let ptr = &mut *ptr; @@ -374,7 +353,9 @@ unsafe extern "C" fn wasi_console_out_seek_memory( 0 => std::io::SeekFrom::Start(seek_to.max(0) as u64), 1 => std::io::SeekFrom::End(seek_to), 2 => std::io::SeekFrom::Current(seek_to), - _ => { return -1; }, + _ => { + return -1; + } }; match ptr.seek(seek_from) { @@ -383,9 +364,7 @@ unsafe extern "C" fn wasi_console_out_seek_memory( } } -unsafe extern "C" fn wasi_console_out_delete_memory( - ptr: *const c_void, /* = *Pipe */ -) -> i64 { +unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void /* = *Pipe */) -> i64 { let ptr = ptr as *const Pipe; let _: Pipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here 0 @@ -395,7 +374,6 @@ unsafe extern "C" fn wasi_console_out_delete_memory( /// for backing stdin / stdout / stderr #[no_mangle] pub unsafe extern "C" fn wasi_console_out_new_memory() -> *mut wasi_console_out_t { - use std::mem::ManuallyDrop; let data = Pipe::new(); @@ -741,9 +719,7 @@ impl Drop for wasi_console_stdin_t { } }; - let error = unsafe { - (self.destructor)((*data).as_mut_ptr() as *const c_void) - }; + let error = unsafe { (self.destructor)((*data).as_mut_ptr() as *const c_void) }; if error < 0 { println!("error dropping wasi_console_stdin_t: {error}"); @@ -803,13 +779,8 @@ impl io::Read for wasi_console_stdin_t { }; let self_on_stdin = self.on_stdin; let data = self.get_data_mut("read")?; - let result = unsafe { - (self_on_stdin)( - data.as_ptr() as *const c_void, - buf.len(), - &mut target, - ) - }; + let result = + unsafe { (self_on_stdin)(data.as_ptr() as *const c_void, buf.len(), &mut target) }; if result >= 0 { for (source, target) in target.response_data.iter().zip(buf.iter_mut()) { *target = *source as u8; From 63d709e6975909c2eb13c91d1f56512d3b3f569b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 22 Aug 2022 15:06:08 +0200 Subject: [PATCH 26/65] Adress review comment: rename wasi_console_out_new -> wasi_pipe_new --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 7acb3c7fe9c..406a9b9f220 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -373,7 +373,7 @@ unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void /* = *Pip /// Creates a new `wasi_console_out_t` which uses a memory buffer /// for backing stdin / stdout / stderr #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_new_memory() -> *mut wasi_console_out_t { +pub unsafe extern "C" fn wasi_pipe_new() -> *mut wasi_console_out_t { use std::mem::ManuallyDrop; let data = Pipe::new(); @@ -1243,8 +1243,8 @@ mod tests { wasm_engine_t* engine = wasm_engine_new(); wasm_store_t* store = wasm_store_new(engine); wasi_config_t* config = wasi_config_new("example_program"); - wasi_console_out_t* override_stdout = wasi_console_out_new_memory(); - wasi_console_out_t* override_stderr = wasi_console_out_new_memory(); + wasi_console_out_t* override_stdout = wasi_pipe_new(); + wasi_console_out_t* override_stderr = wasi_pipe_new(); CustomWasiStdin stdin = { .invocation = 0 }; wasi_console_stdin_t* override_stdin = wasi_console_stdin_new( From 67ed6249994e80c4d6b2ae707aedf0c58b70d790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 30 Aug 2022 14:18:04 +0200 Subject: [PATCH 27/65] Fix make lint --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 406a9b9f220..4eadb58f428 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -533,7 +533,7 @@ pub unsafe extern "C" fn wasi_console_out_seek( pub unsafe extern "C" fn wasi_console_out_clone( ptr: *const wasi_console_out_t, ) -> *mut wasi_console_out_t { - Box::leak(Box::new((&*ptr).clone())) + Box::leak(Box::new((*ptr).clone())) } #[derive(Debug)] From b046463b1dd8fa02b5cd8c63083f07ec52115932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 6 Sep 2022 15:20:44 +0200 Subject: [PATCH 28/65] Implement Write + Seek for WasiPipe --- lib/wasi/src/state/pipe.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 12c0084d43d..a999130c3d1 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -2,7 +2,7 @@ use crate::syscalls::types::*; use crate::syscalls::{read_bytes, write_bytes}; use bytes::{Buf, Bytes}; use std::convert::TryInto; -use std::io::{self, Read}; +use std::io::{self, Read, Write, Seek, SeekFrom}; use std::ops::DerefMut; use std::sync::mpsc; use std::sync::Mutex; @@ -93,6 +93,24 @@ impl WasiPipe { } } +impl Write for WasiPipe { + fn write(&mut self, buf: &[u8]) -> io::Result { + let buf_len = buf.len(); + let tx = self.tx.lock().unwrap(); + tx.send(buf.to_vec()).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{e}")))?; + Ok(buf_len) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Seek for WasiPipe { + fn seek(&mut self, _: SeekFrom) -> io::Result { + Ok(0) + } +} + impl Read for WasiPipe { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { loop { From fac6d0ff2e44fb1ba0d670951f1a5ffdd8483512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 6 Sep 2022 15:53:12 +0200 Subject: [PATCH 29/65] Added WasiPipePair to make the transition to two pipes easier --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 42 +++++++------ lib/wasi/src/lib.rs | 4 +- lib/wasi/src/state/pipe.rs | 93 ++++++++++++++++++++++++++-- lib/wasi/src/state/types.rs | 74 ---------------------- lib/wasi/src/syscalls/mod.rs | 4 +- tests/lib/wast/src/wasi_wast.rs | 4 +- 6 files changed, 119 insertions(+), 102 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 4eadb58f428..92f9f403a06 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -23,8 +23,8 @@ use std::{ sync::MutexGuard, }; use wasmer_wasi::{ - get_wasi_version, FsError, Pipe, VirtualFile, WasiFile, WasiFunctionEnv, WasiState, - WasiStateBuilder, WasiVersion, + get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiState, + WasiStateBuilder, WasiVersion, WasiPipePair, }; /// Function callback that takes: @@ -300,39 +300,39 @@ extern "C" fn wasi_console_out_delete_null(_: *const c_void) -> i64 { } unsafe extern "C" fn wasi_console_out_read_memory( - ptr: *const c_void, /* = *Pipe */ + ptr: *const c_void, /* = *WasiPipePair */ byte_ptr: *mut c_char, /* &[u8] bytes to read */ max_bytes: usize, /* max bytes to read */ ) -> i64 { use std::io::Read; - let ptr = ptr as *mut Pipe; + let ptr = ptr as *mut WasiPipePair; let ptr = &mut *ptr; let slice = std::slice::from_raw_parts_mut(byte_ptr as *mut u8, max_bytes); - match ptr.read(slice) { + match ptr.recv.read(slice) { Ok(o) => o as i64, Err(_) => -1, } } unsafe extern "C" fn wasi_console_out_write_memory( - ptr: *const c_void, /* = *Pipe */ + ptr: *const c_void, /* = *WasiPipePair */ byte_ptr: *const c_char, byte_len: usize, flush: bool, ) -> i64 { use std::io::Write; - let ptr = ptr as *mut Pipe; + let ptr = ptr as *mut WasiPipePair; let ptr = &mut *ptr; if flush { - match ptr.flush() { + match ptr.send.flush() { Ok(()) => 0, Err(_) => -1, } } else { let slice = std::slice::from_raw_parts(byte_ptr as *const u8, byte_len); - match ptr.write(slice) { + match ptr.send.write(slice) { Ok(o) => o as i64, Err(_) => -1, } @@ -340,13 +340,13 @@ unsafe extern "C" fn wasi_console_out_write_memory( } unsafe extern "C" fn wasi_console_out_seek_memory( - ptr: *const c_void, /* = *Pipe */ + ptr: *const c_void, /* = *WasiPipePair */ direction: c_char, seek_to: i64, ) -> i64 { use std::io::Seek; - let ptr = ptr as *mut Pipe; + let ptr = ptr as *mut WasiPipePair; let ptr = &mut *ptr; let seek_from = match direction { @@ -358,15 +358,15 @@ unsafe extern "C" fn wasi_console_out_seek_memory( } }; - match ptr.seek(seek_from) { + match ptr.recv.seek(seek_from) { Ok(o) => o as i64, Err(_) => -1, } } -unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void /* = *Pipe */) -> i64 { - let ptr = ptr as *const Pipe; - let _: Pipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here +unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void /* = *WasiPipe */) -> i64 { + let ptr = ptr as *const WasiPipePair; + let _: WasiPipePair = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here 0 } @@ -376,9 +376,13 @@ unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void /* = *Pip pub unsafe extern "C" fn wasi_pipe_new() -> *mut wasi_console_out_t { use std::mem::ManuallyDrop; - let data = Pipe::new(); - let mut data = ManuallyDrop::new(data); - let ptr: &mut Pipe = &mut data; + let (send, recv) = WasiPipe::new(); + let pair = WasiPipePair { + send, + recv, + }; + let mut data = ManuallyDrop::new(pair); + let ptr: &mut WasiPipePair = &mut data; wasi_console_out_new( wasi_console_out_read_memory, @@ -386,7 +390,7 @@ pub unsafe extern "C" fn wasi_pipe_new() -> *mut wasi_console_out_t { wasi_console_out_seek_memory, wasi_console_out_delete_memory, ptr as *mut _ as *mut c_void, - std::mem::size_of::(), + std::mem::size_of::(), ) } diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index d4971f50f15..f06dd29de7f 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -43,8 +43,8 @@ mod utils; use crate::syscalls::*; pub use crate::state::{ - Fd, Pipe, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder, - WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, + Fd, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder, + WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, WasiPipe, WasiPipePair, }; pub use crate::syscalls::types; #[cfg(feature = "wasix")] diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index a999130c3d1..681e145574c 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -2,12 +2,13 @@ use crate::syscalls::types::*; use crate::syscalls::{read_bytes, write_bytes}; use bytes::{Buf, Bytes}; use std::convert::TryInto; -use std::io::{self, Read, Write, Seek, SeekFrom}; +use std::io::{self, Read, Seek, SeekFrom, Write}; use std::ops::DerefMut; use std::sync::mpsc; use std::sync::Mutex; use wasmer::WasmSlice; use wasmer::{MemorySize, MemoryView}; +use wasmer_vfs::{FsError, VirtualFile}; #[derive(Debug)] pub struct WasiPipe { @@ -19,8 +20,59 @@ pub struct WasiPipe { read_buffer: Option, } +#[derive(Debug)] +pub struct WasiPipePair { + pub send: WasiPipe, + pub recv: WasiPipe, +} + +impl Write for WasiPipePair { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.send.write(buf) + } + fn flush(&mut self) -> io::Result<()> { + self.send.flush() + } +} + +impl Seek for WasiPipePair { + fn seek(&mut self, _: SeekFrom) -> io::Result { + Ok(0) + } +} + +impl Read for WasiPipePair { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.recv.read(buf) + } +} + +impl VirtualFile for WasiPipePair { + fn last_accessed(&self) -> u64 { + self.recv.last_accessed() + } + fn last_modified(&self) -> u64 { + self.recv.last_modified() + } + fn created_time(&self) -> u64 { + self.recv.created_time() + } + fn size(&self) -> u64 { + self.recv.size() + } + fn set_len(&mut self, i: u64) -> Result<(), FsError> { + self.recv.set_len(i) + } + fn unlink(&mut self) -> Result<(), FsError> { + self.recv.unlink() + } + fn bytes_available_read(&self) -> Result, FsError> { + self.recv.bytes_available_read() + } +} + impl WasiPipe { - pub fn new() -> (WasiPipe, WasiPipe) { + pub fn new() -> WasiPipePair { let (tx1, rx1) = mpsc::channel(); let (tx2, rx2) = mpsc::channel(); @@ -36,7 +88,7 @@ impl WasiPipe { read_buffer: None, }; - (pipe1, pipe2) + WasiPipePair { send: pipe1, recv: pipe2 } } pub fn recv( @@ -97,7 +149,8 @@ impl Write for WasiPipe { fn write(&mut self, buf: &[u8]) -> io::Result { let buf_len = buf.len(); let tx = self.tx.lock().unwrap(); - tx.send(buf.to_vec()).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{e}")))?; + tx.send(buf.to_vec()) + .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{e}")))?; Ok(buf_len) } fn flush(&mut self) -> io::Result<()> { @@ -134,3 +187,35 @@ impl Read for WasiPipe { } } } + +impl VirtualFile for WasiPipe { + fn last_accessed(&self) -> u64 { + 0 + } + fn last_modified(&self) -> u64 { + 0 + } + fn created_time(&self) -> u64 { + 0 + } + fn size(&self) -> u64 { + self.read_buffer + .as_ref() + .map(|s| s.len() as u64) + .unwrap_or_default() + } + fn set_len(&mut self, _: u64) -> Result<(), FsError> { + Ok(()) + } + fn unlink(&mut self) -> Result<(), FsError> { + Ok(()) + } + fn bytes_available_read(&self) -> Result, FsError> { + Ok(Some( + self.read_buffer + .as_ref() + .map(|s| s.len()) + .unwrap_or_default(), + )) + } +} diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 462a008f19f..671f58dd03f 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -375,80 +375,6 @@ pub(crate) fn poll( pub trait WasiPath {} -/// For piping stdio. Stores all output / input in a byte-vector. -#[derive(Debug, Clone, Default)] -#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub struct Pipe { - buffer: Arc>>, -} - -impl Pipe { - pub fn new() -> Self { - Self::default() - } -} - -impl Read for Pipe { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let mut buffer = self.buffer.lock().unwrap(); - let amt = std::cmp::min(buf.len(), buffer.len()); - let buf_iter = buffer.drain(..amt).enumerate(); - for (i, byte) in buf_iter { - buf[i] = byte; - } - Ok(amt) - } -} - -impl Write for Pipe { - fn write(&mut self, buf: &[u8]) -> io::Result { - let mut buffer = self.buffer.lock().unwrap(); - buffer.extend(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Seek for Pipe { - fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { - Err(io::Error::new( - io::ErrorKind::Other, - "can not seek in a pipe", - )) - } -} - -//#[cfg_attr(feature = "enable-serde", typetag::serde)] -impl VirtualFile for Pipe { - fn last_accessed(&self) -> u64 { - 0 - } - fn last_modified(&self) -> u64 { - 0 - } - fn created_time(&self) -> u64 { - 0 - } - fn size(&self) -> u64 { - let buffer = self.buffer.lock().unwrap(); - buffer.len() as u64 - } - fn set_len(&mut self, len: u64) -> Result<(), FsError> { - let mut buffer = self.buffer.lock().unwrap(); - buffer.resize(len as usize, 0); - Ok(()) - } - fn unlink(&mut self) -> Result<(), FsError> { - Ok(()) - } - fn bytes_available_read(&self) -> Result, FsError> { - let buffer = self.buffer.lock().unwrap(); - Ok(Some(buffer.len())) - } -} - /* TODO: Think about using this trait WasiFdBacking: std::fmt::Debug { diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 903abae2a27..ce630cdac4e 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -1807,7 +1807,9 @@ pub fn fd_pipe( let env = ctx.data(); let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); - let (pipe1, pipe2) = WasiPipe::new(); + let pipes = WasiPipe::new(); + let pipe1 = pipes.send; + let pipe2 = pipes.recv; let inode1 = state.fs.create_inode_with_default_stat( inodes.deref_mut(), diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 6b2e13aac4c..40f72ca7e04 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -8,7 +8,7 @@ use wasmer::{Imports, Instance, Module, Store}; use wasmer_vfs::{host_fs, mem_fs, FileSystem}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; use wasmer_wasi::{ - generate_import_object_from_env, get_wasi_version, FsError, Pipe, VirtualFile, WasiEnv, + generate_import_object_from_env, get_wasi_version, FsError, WasiPipe, VirtualFile, WasiEnv, WasiFunctionEnv, WasiState, WasiVersion, }; use wast::parser::{self, Parse, ParseBuffer, Parser}; @@ -143,7 +143,7 @@ impl<'a> WasiTest<'a> { )> { let mut builder = WasiState::new(self.wasm_path); - let stdin_pipe = Pipe::new(); + let stdin_pipe = WasiPipe::new(); builder.stdin(Box::new(stdin_pipe)); for (name, value) in &self.envs { From 8bf26a30f4f85041d10f8176a1cfb9a1ad4a3ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 6 Sep 2022 16:17:34 +0200 Subject: [PATCH 30/65] cargo fmt --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 11 ++++------- lib/wasi/src/lib.rs | 4 ++-- lib/wasi/src/state/pipe.rs | 5 ++++- tests/lib/wast/src/wasi_wast.rs | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 92f9f403a06..7d2d02d9e07 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -23,8 +23,8 @@ use std::{ sync::MutexGuard, }; use wasmer_wasi::{ - get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiState, - WasiStateBuilder, WasiVersion, WasiPipePair, + get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiPipePair, + WasiState, WasiStateBuilder, WasiVersion, }; /// Function callback that takes: @@ -364,7 +364,7 @@ unsafe extern "C" fn wasi_console_out_seek_memory( } } -unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void /* = *WasiPipe */) -> i64 { +unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void, /* = *WasiPipe */) -> i64 { let ptr = ptr as *const WasiPipePair; let _: WasiPipePair = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here 0 @@ -377,10 +377,7 @@ pub unsafe extern "C" fn wasi_pipe_new() -> *mut wasi_console_out_t { use std::mem::ManuallyDrop; let (send, recv) = WasiPipe::new(); - let pair = WasiPipePair { - send, - recv, - }; + let pair = WasiPipePair { send, recv }; let mut data = ManuallyDrop::new(pair); let ptr: &mut WasiPipePair = &mut data; diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index f06dd29de7f..65664efd00f 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -43,8 +43,8 @@ mod utils; use crate::syscalls::*; pub use crate::state::{ - Fd, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder, - WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, WasiPipe, WasiPipePair, + Fd, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiPipe, WasiPipePair, WasiState, + WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, }; pub use crate::syscalls::types; #[cfg(feature = "wasix")] diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 681e145574c..e474fc86b16 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -88,7 +88,10 @@ impl WasiPipe { read_buffer: None, }; - WasiPipePair { send: pipe1, recv: pipe2 } + WasiPipePair { + send: pipe1, + recv: pipe2, + } } pub fn recv( diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 40f72ca7e04..f899402e83d 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -8,8 +8,8 @@ use wasmer::{Imports, Instance, Module, Store}; use wasmer_vfs::{host_fs, mem_fs, FileSystem}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; use wasmer_wasi::{ - generate_import_object_from_env, get_wasi_version, FsError, WasiPipe, VirtualFile, WasiEnv, - WasiFunctionEnv, WasiState, WasiVersion, + generate_import_object_from_env, get_wasi_version, FsError, VirtualFile, WasiEnv, + WasiFunctionEnv, WasiPipe, WasiState, WasiVersion, }; use wast::parser::{self, Parse, ParseBuffer, Parser}; From dcadaf22d8377ace43dae1b52f529f9b0b37029b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 6 Sep 2022 17:30:29 +0200 Subject: [PATCH 31/65] Added intial API for creating two-channel pipes --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 140 ++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 2 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 7d2d02d9e07..bae7387d1ca 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -314,6 +314,21 @@ unsafe extern "C" fn wasi_console_out_read_memory( } } +unsafe extern "C" fn wasi_console_out_read_memory_2( + ptr: *const c_void, /* = *WasiPipe */ + byte_ptr: *mut c_char, /* &[u8] bytes to read */ + max_bytes: usize, /* max bytes to read */ +) -> i64 { + use std::io::Read; + let ptr = ptr as *mut WasiPipe; + let ptr = &mut *ptr; + let slice = std::slice::from_raw_parts_mut(byte_ptr as *mut u8, max_bytes); + match ptr.read(slice) { + Ok(o) => o as i64, + Err(_) => -1, + } +} + unsafe extern "C" fn wasi_console_out_write_memory( ptr: *const c_void, /* = *WasiPipePair */ byte_ptr: *const c_char, @@ -339,6 +354,31 @@ unsafe extern "C" fn wasi_console_out_write_memory( } } +unsafe extern "C" fn wasi_console_out_write_memory_2( + ptr: *const c_void, /* = *WasiPipe */ + byte_ptr: *const c_char, + byte_len: usize, + flush: bool, +) -> i64 { + use std::io::Write; + + let ptr = ptr as *mut WasiPipe; + let ptr = &mut *ptr; + + if flush { + match ptr.flush() { + Ok(()) => 0, + Err(_) => -1, + } + } else { + let slice = std::slice::from_raw_parts(byte_ptr as *const u8, byte_len); + match ptr.write(slice) { + Ok(o) => o as i64, + Err(_) => -1, + } + } +} + unsafe extern "C" fn wasi_console_out_seek_memory( ptr: *const c_void, /* = *WasiPipePair */ direction: c_char, @@ -364,20 +404,82 @@ unsafe extern "C" fn wasi_console_out_seek_memory( } } + +unsafe extern "C" fn wasi_console_out_seek_memory_2( + ptr: *const c_void, /* = *WasiPipe */ + direction: c_char, + seek_to: i64, +) -> i64 { + use std::io::Seek; + + let ptr = ptr as *mut WasiPipe; + let ptr = &mut *ptr; + + let seek_from = match direction { + 0 => std::io::SeekFrom::Start(seek_to.max(0) as u64), + 1 => std::io::SeekFrom::End(seek_to), + 2 => std::io::SeekFrom::Current(seek_to), + _ => { + return -1; + } + }; + + match ptr.seek(seek_from) { + Ok(o) => o as i64, + Err(_) => -1, + } +} + unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void, /* = *WasiPipe */) -> i64 { let ptr = ptr as *const WasiPipePair; let _: WasiPipePair = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here 0 } +#[no_mangle] +unsafe extern "C" fn wasi_console_out_delete_memory_2(ptr: *const c_void, /* = *WasiPipe */) -> i64 { + let ptr = ptr as *const WasiPipe; + let _: WasiPipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_pipe_new_2(ptr_user: &mut *mut wasi_console_out_t) -> *mut wasi_console_out_t { + use std::mem::ManuallyDrop; + + let pair = WasiPipe::new(); + + let mut data1 = ManuallyDrop::new(pair.send); + let ptr1: &mut WasiPipe = &mut data1; + + *ptr_user = wasi_console_out_new( + wasi_console_out_read_memory_2, + wasi_console_out_write_memory_2, + wasi_console_out_seek_memory_2, + wasi_console_out_delete_memory_2, + ptr1 as *mut _ as *mut c_void, + std::mem::size_of::(), + ); + + let mut data2 = ManuallyDrop::new(pair.recv); + let ptr2: &mut WasiPipe = &mut data2; + wasi_console_out_new( + wasi_console_out_read_memory_2, + wasi_console_out_write_memory_2, + wasi_console_out_seek_memory_2, + wasi_console_out_delete_memory_2, + ptr2 as *mut _ as *mut c_void, + std::mem::size_of::(), + ) +} + /// Creates a new `wasi_console_out_t` which uses a memory buffer /// for backing stdin / stdout / stderr #[no_mangle] pub unsafe extern "C" fn wasi_pipe_new() -> *mut wasi_console_out_t { use std::mem::ManuallyDrop; - let (send, recv) = WasiPipe::new(); - let pair = WasiPipePair { send, recv }; + let pair = WasiPipe::new(); let mut data = ManuallyDrop::new(pair); let ptr: &mut WasiPipePair = &mut data; @@ -1205,6 +1307,38 @@ mod tests { .success(); } + #[test] + fn test_wasi_stdin_set() { + (assert_c! { + #include "tests/wasmer.h" + #include "string.h" + #include "stdio.h" + + int main() { + wasi_console_out_t* override_stdout_1 = NULL; + wasi_console_out_t* override_stdout_2 = wasi_pipe_new_2(&override_stdout_1); + + assert(override_stdout_1); + assert(override_stdout_2); + + // write to override_stdout_1, then close override_stdout_1 + wasi_console_out_write_str(override_stdout_1, "test"); + wasi_console_out_delete(override_stdout_1); + + // read from override_stdout_2, after override_stdout_1 has been closed so it doesn't block + char* out; + wasi_console_out_read_str(override_stdout_2, &out); + assert(strcmp(out, "test") == 0); + wasi_console_out_delete_str(out); + + // cleanup + wasi_console_out_delete(override_stdout_2); + return 0; + } + }).success(); + } + + /* #[test] fn test_wasi_stdin_set() { (assert_c! { @@ -1392,4 +1526,6 @@ mod tests { }) .success(); } + */ + } From 2a5d267a2b9b5111f3b158c62878e206c5b1d3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 6 Sep 2022 19:35:46 +0200 Subject: [PATCH 32/65] Added WasiPipe test to test reading / writing --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 11 +++++++---- lib/wasi/src/state/pipe.rs | 13 +++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index bae7387d1ca..e2b6f35d874 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -135,9 +135,10 @@ impl io::Read for wasi_console_out_t { let self_read = self.read; let mut data = self.get_data_mut("read")?; let result = unsafe { + let ptr = buf.as_mut_ptr() as *mut c_char; (self_read)( data.as_mut_ptr() as *const c_void, - buf.as_mut_ptr() as *mut c_char, + ptr, buf.len(), ) }; @@ -323,10 +324,11 @@ unsafe extern "C" fn wasi_console_out_read_memory_2( let ptr = ptr as *mut WasiPipe; let ptr = &mut *ptr; let slice = std::slice::from_raw_parts_mut(byte_ptr as *mut u8, max_bytes); - match ptr.read(slice) { + let r = match ptr.read(slice) { Ok(o) => o as i64, Err(_) => -1, - } + }; + r } unsafe extern "C" fn wasi_console_out_write_memory( @@ -439,7 +441,8 @@ unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void, /* = *Wa #[no_mangle] unsafe extern "C" fn wasi_console_out_delete_memory_2(ptr: *const c_void, /* = *WasiPipe */) -> i64 { let ptr = ptr as *const WasiPipe; - let _: WasiPipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here + let mut pipe: WasiPipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here + pipe.close(); 0 } diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index e474fc86b16..9b2e1a42e9b 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -180,12 +180,13 @@ impl Read for WasiPipe { } } let rx = self.rx.lock().unwrap(); - let data = rx.recv().map_err(|_| { - io::Error::new( - io::ErrorKind::BrokenPipe, - "the wasi pipe is not connected".to_string(), - ) - })?; + let data = match rx.recv() { + Ok(o) => o, + // Errors can happen if the sender has been dropped already + // In this case, just return 0 to indicate that we can't read any + // bytes anymore + Err(_) => { return Ok(0); }, + }; self.read_buffer.replace(Bytes::from(data)); } } From d26edf9ac6f328f91fa5eeaf671e845039fec3a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 6 Sep 2022 20:00:47 +0200 Subject: [PATCH 33/65] C-API: Implement stdio override with WasiPipe instead of custom impl --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 393 ++++----------------------- lib/wasi/src/state/pipe.rs | 6 +- 2 files changed, 59 insertions(+), 340 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index e2b6f35d874..bbb2630c67f 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -23,8 +23,8 @@ use std::{ sync::MutexGuard, }; use wasmer_wasi::{ - get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiPipePair, - WasiState, WasiStateBuilder, WasiVersion, + get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiState, + WasiStateBuilder, WasiVersion, }; /// Function callback that takes: @@ -38,21 +38,6 @@ pub type WasiConsoleIoWriteCallback = unsafe extern "C" fn(*const c_void, *const c_char, usize, bool) -> i64; pub type WasiConsoleIoSeekCallback = unsafe extern "C" fn(*const c_void, c_char, i64) -> i64; pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void) -> i64; -/// Callback that is activated whenever the program wants to read from stdin -/// -/// Parameters: -/// - `void*`: to user-defined data -/// - `usize`: sizeof(user-defined data) -/// - `usize`: alignof(user-defined data) -/// - `usize`: maximum bytes that can be written to stdin -/// - `*mut wasi_console_stdin_response_t`: handle to the stdin response, used to write data to stdin -/// -/// The function returning is the same as the program receiving an "enter" -/// key event from the console I/O. With the custom environment pointer (the first argument) -/// you can clone references to the stdout channel and - for example - inspect the stdout -/// channel to answer depending on runtime-dependent stdout data. -pub type WasiConsoleIoOnStdinCallback = - unsafe extern "C" fn(*const c_void, usize, *mut wasi_console_stdin_response_t) -> i64; /// The console override is a custom context consisting of callback pointers /// (which are activated whenever some console I/O occurs) and a "context", which @@ -136,11 +121,7 @@ impl io::Read for wasi_console_out_t { let mut data = self.get_data_mut("read")?; let result = unsafe { let ptr = buf.as_mut_ptr() as *mut c_char; - (self_read)( - data.as_mut_ptr() as *const c_void, - ptr, - buf.len(), - ) + (self_read)(data.as_mut_ptr() as *const c_void, ptr, buf.len()) }; if result >= 0 { Ok(result as usize) @@ -284,6 +265,7 @@ pub unsafe extern "C" fn wasi_console_out_new_null() -> *mut wasi_console_out_t extern "C" fn wasi_console_out_read_null(_: *const c_void, _: *mut c_char, _: usize) -> i64 { 0 } + extern "C" fn wasi_console_out_write_null( _: *const c_void, _: *const c_char, @@ -292,6 +274,7 @@ extern "C" fn wasi_console_out_write_null( ) -> i64 { 0 } + extern "C" fn wasi_console_out_seek_null(_: *const c_void, _: c_char, _: i64) -> i64 { 0 } @@ -300,21 +283,6 @@ extern "C" fn wasi_console_out_delete_null(_: *const c_void) -> i64 { 0 } -unsafe extern "C" fn wasi_console_out_read_memory( - ptr: *const c_void, /* = *WasiPipePair */ - byte_ptr: *mut c_char, /* &[u8] bytes to read */ - max_bytes: usize, /* max bytes to read */ -) -> i64 { - use std::io::Read; - let ptr = ptr as *mut WasiPipePair; - let ptr = &mut *ptr; - let slice = std::slice::from_raw_parts_mut(byte_ptr as *mut u8, max_bytes); - match ptr.recv.read(slice) { - Ok(o) => o as i64, - Err(_) => -1, - } -} - unsafe extern "C" fn wasi_console_out_read_memory_2( ptr: *const c_void, /* = *WasiPipe */ byte_ptr: *mut c_char, /* &[u8] bytes to read */ @@ -331,31 +299,6 @@ unsafe extern "C" fn wasi_console_out_read_memory_2( r } -unsafe extern "C" fn wasi_console_out_write_memory( - ptr: *const c_void, /* = *WasiPipePair */ - byte_ptr: *const c_char, - byte_len: usize, - flush: bool, -) -> i64 { - use std::io::Write; - - let ptr = ptr as *mut WasiPipePair; - let ptr = &mut *ptr; - - if flush { - match ptr.send.flush() { - Ok(()) => 0, - Err(_) => -1, - } - } else { - let slice = std::slice::from_raw_parts(byte_ptr as *const u8, byte_len); - match ptr.send.write(slice) { - Ok(o) => o as i64, - Err(_) => -1, - } - } -} - unsafe extern "C" fn wasi_console_out_write_memory_2( ptr: *const c_void, /* = *WasiPipe */ byte_ptr: *const c_char, @@ -381,32 +324,6 @@ unsafe extern "C" fn wasi_console_out_write_memory_2( } } -unsafe extern "C" fn wasi_console_out_seek_memory( - ptr: *const c_void, /* = *WasiPipePair */ - direction: c_char, - seek_to: i64, -) -> i64 { - use std::io::Seek; - - let ptr = ptr as *mut WasiPipePair; - let ptr = &mut *ptr; - - let seek_from = match direction { - 0 => std::io::SeekFrom::Start(seek_to.max(0) as u64), - 1 => std::io::SeekFrom::End(seek_to), - 2 => std::io::SeekFrom::Current(seek_to), - _ => { - return -1; - } - }; - - match ptr.recv.seek(seek_from) { - Ok(o) => o as i64, - Err(_) => -1, - } -} - - unsafe extern "C" fn wasi_console_out_seek_memory_2( ptr: *const c_void, /* = *WasiPipe */ direction: c_char, @@ -432,26 +349,26 @@ unsafe extern "C" fn wasi_console_out_seek_memory_2( } } -unsafe extern "C" fn wasi_console_out_delete_memory(ptr: *const c_void, /* = *WasiPipe */) -> i64 { - let ptr = ptr as *const WasiPipePair; - let _: WasiPipePair = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here - 0 -} - #[no_mangle] -unsafe extern "C" fn wasi_console_out_delete_memory_2(ptr: *const c_void, /* = *WasiPipe */) -> i64 { +unsafe extern "C" fn wasi_console_out_delete_memory_2( + ptr: *const c_void, /* = *WasiPipe */ +) -> i64 { let ptr = ptr as *const WasiPipe; let mut pipe: WasiPipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here pipe.close(); 0 } +/// Creates a new `wasi_console_out_t` which uses a memory buffer +/// for backing stdin / stdout / stderr #[no_mangle] -pub unsafe extern "C" fn wasi_pipe_new_2(ptr_user: &mut *mut wasi_console_out_t) -> *mut wasi_console_out_t { +pub unsafe extern "C" fn wasi_pipe_new( + ptr_user: &mut *mut wasi_console_out_t, +) -> *mut wasi_console_out_t { use std::mem::ManuallyDrop; let pair = WasiPipe::new(); - + let mut data1 = ManuallyDrop::new(pair.send); let ptr1: &mut WasiPipe = &mut data1; @@ -476,26 +393,6 @@ pub unsafe extern "C" fn wasi_pipe_new_2(ptr_user: &mut *mut wasi_console_out_t) ) } -/// Creates a new `wasi_console_out_t` which uses a memory buffer -/// for backing stdin / stdout / stderr -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_new() -> *mut wasi_console_out_t { - use std::mem::ManuallyDrop; - - let pair = WasiPipe::new(); - let mut data = ManuallyDrop::new(pair); - let ptr: &mut WasiPipePair = &mut data; - - wasi_console_out_new( - wasi_console_out_read_memory, - wasi_console_out_write_memory, - wasi_console_out_seek_memory, - wasi_console_out_delete_memory, - ptr as *mut _ as *mut c_void, - std::mem::size_of::(), - ) -} - #[no_mangle] pub unsafe extern "C" fn wasi_console_out_delete(ptr: *mut wasi_console_out_t) -> bool { let _ = Box::from_raw(ptr); @@ -635,13 +532,6 @@ pub unsafe extern "C" fn wasi_console_out_seek( .unwrap_or(-1) } -#[no_mangle] -pub unsafe extern "C" fn wasi_console_out_clone( - ptr: *const wasi_console_out_t, -) -> *mut wasi_console_out_t { - Box::leak(Box::new((*ptr).clone())) -} - #[derive(Debug)] #[allow(non_camel_case_types)] pub struct wasi_config_t { @@ -782,165 +672,10 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { config.inherit_stdin = None; } -#[allow(clippy::box_collection, clippy::redundant_allocation)] -#[repr(C)] -pub struct wasi_console_stdin_t { - on_stdin: WasiConsoleIoOnStdinCallback, - destructor: WasiConsoleIoEnvDestructor, - data: Option>>, -} - -impl wasi_console_stdin_t { - fn get_data_mut(&mut self, op_id: &'static str) -> io::Result<&mut Vec> { - self.data.as_deref_mut().ok_or_else(|| { - io::Error::new( - io::ErrorKind::Other, - format!("could not get env data ({op_id}) on wasi_console_stdin_t"), - ) - }) - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_console_stdin_new( - on_stdin: WasiConsoleIoOnStdinCallback, - destructor: WasiConsoleIoEnvDestructor, - ptr: *const c_void, - len: usize, -) -> *mut wasi_console_stdin_t { - let data = std::slice::from_raw_parts(ptr as *const c_char, len); - Box::leak(Box::new(wasi_console_stdin_t { - on_stdin, - destructor, - data: Some(Box::new(data.to_vec())), - })) -} - -impl Drop for wasi_console_stdin_t { - fn drop(&mut self) { - let mut data = match self.data.take() { - Some(s) => s, - None => { - return; - } - }; - - let error = unsafe { (self.destructor)((*data).as_mut_ptr() as *const c_void) }; - - if error < 0 { - println!("error dropping wasi_console_stdin_t: {error}"); - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_console_stdin_delete(ptr: *mut wasi_console_stdin_t) -> bool { - let _ = Box::from_raw(ptr); - true -} - -#[allow(clippy::box_collection, clippy::redundant_allocation)] -#[derive(Clone)] -#[repr(C)] -pub struct wasi_console_stdin_response_t { - // data that is written to the response - response_data: Box>, -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_console_stdin_response_write_bytes( - response_t: &mut wasi_console_stdin_response_t, - bytes: *const c_char, - len: usize, -) -> i64 { - let slice = std::slice::from_raw_parts(bytes, len); - response_t.response_data.extend_from_slice(slice); - slice.len() as i64 -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_console_stdin_response_write_str( - response_t: &mut wasi_console_stdin_response_t, - str: *const c_char, -) -> i64 { - let c_str = CStr::from_ptr(str); - let bytes = c_str.to_bytes(); - wasi_console_stdin_response_write_bytes( - response_t, - bytes.as_ptr() as *const c_char, - bytes.len(), - ) -} - -impl fmt::Debug for wasi_console_stdin_t { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "wasi_console_stdin_t") - } -} - -impl io::Read for wasi_console_stdin_t { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let mut target = wasi_console_stdin_response_t { - response_data: Box::new(Vec::new()), - }; - let self_on_stdin = self.on_stdin; - let data = self.get_data_mut("read")?; - let result = - unsafe { (self_on_stdin)(data.as_ptr() as *const c_void, buf.len(), &mut target) }; - if result >= 0 { - for (source, target) in target.response_data.iter().zip(buf.iter_mut()) { - *target = *source as u8; - } - Ok(result as usize) - } else { - Err(io::Error::new( - io::ErrorKind::Other, - format!("could not read from wasi_console_out_t: {result}"), - )) - } - } -} - -impl io::Write for wasi_console_stdin_t { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl io::Seek for wasi_console_stdin_t { - fn seek(&mut self, _: SeekFrom) -> io::Result { - Ok(0) - } -} - -impl VirtualFile for wasi_console_stdin_t { - fn last_accessed(&self) -> u64 { - 0 - } - fn last_modified(&self) -> u64 { - 0 - } - fn created_time(&self) -> u64 { - 0 - } - fn size(&self) -> u64 { - 0 - } - fn set_len(&mut self, _: u64) -> Result<(), FsError> { - Ok(()) - } - fn unlink(&mut self) -> Result<(), FsError> { - Ok(()) - } -} - #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdin( config: &mut wasi_config_t, - stdin: *mut wasi_console_stdin_t, + stdin: *mut wasi_console_out_t, ) { config.state_builder.stdin(Box::from_raw(stdin)); } @@ -1319,8 +1054,8 @@ mod tests { int main() { wasi_console_out_t* override_stdout_1 = NULL; - wasi_console_out_t* override_stdout_2 = wasi_pipe_new_2(&override_stdout_1); - + wasi_console_out_t* override_stdout_2 = wasi_pipe_new(&override_stdout_1); + assert(override_stdout_1); assert(override_stdout_2); @@ -1338,69 +1073,47 @@ mod tests { wasi_console_out_delete(override_stdout_2); return 0; } - }).success(); + }) + .success(); } - /* #[test] - fn test_wasi_stdin_set() { + fn test_wasi_stdin_set_2() { (assert_c! { #include "tests/wasmer.h" #include "string.h" #include "stdio.h" - typedef struct { - int invocation; - } CustomWasiStdin; - - int64_t CustomWasiStdin_destructor( - const void* env - ) { - (void)env; - return 0; - } - - int64_t CustomWasiStdin_onStdIn( - const void* env, - uintptr_t maxwrite, - wasi_console_stdin_response_t* in - ) { - CustomWasiStdin* ptr = (CustomWasiStdin*)env; - (void)maxwrite; - if (ptr->invocation == 0) { - wasi_console_stdin_response_write_str(in, "hello"); - ptr->invocation += 1; - return 5; // sizeof("hello") - } else { - return 0; - } - } - int main() { wasm_engine_t* engine = wasm_engine_new(); wasm_store_t* store = wasm_store_new(engine); wasi_config_t* config = wasi_config_new("example_program"); - wasi_console_out_t* override_stdout = wasi_pipe_new(); - wasi_console_out_t* override_stderr = wasi_pipe_new(); - - CustomWasiStdin stdin = { .invocation = 0 }; - wasi_console_stdin_t* override_stdin = wasi_console_stdin_new( - CustomWasiStdin_onStdIn, - CustomWasiStdin_destructor, - &stdin, - sizeof(stdin) - ); - - // Cloning the `wasi_console_out_t` does not deep-clone the - // internal stream, since that is locked behind an Arc>. - wasi_console_out_t* stdout_receiver = wasi_console_out_clone(override_stdout); - wasi_console_out_t* stderr_receiver = wasi_console_out_clone(override_stderr); + + wasi_console_out_t* override_stdout_1 = NULL; + wasi_console_out_t* override_stdout_2 = wasi_pipe_new(&override_stdout_1); + assert(override_stdout_1); + assert(override_stdout_2); + + wasi_console_out_t* override_stderr_1 = NULL; + wasi_console_out_t* override_stderr_2 = wasi_pipe_new(&override_stderr_1); + assert(override_stderr_1); + assert(override_stderr_2); + + wasi_console_out_t* override_stdin_1 = NULL; + wasi_console_out_t* override_stdin_2 = wasi_pipe_new(&override_stdin_1); + assert(override_stdin_1); + assert(override_stdin_2); // The override_stdin ownership is moved to the config - wasi_config_overwrite_stdin(config, override_stdin); - wasi_config_overwrite_stdout(config, override_stdout); - wasi_config_overwrite_stderr(config, override_stderr); + wasi_config_overwrite_stdin(config, override_stdin_1); + wasi_config_overwrite_stdout(config, override_stdout_1); + wasi_config_overwrite_stderr(config, override_stderr_1); + + // write to stdin, then close all senders in order not to block + // during execution + wasi_console_out_write_str(override_stdin_2, "hello"); + wasi_console_out_delete(override_stdin_2); // Load binary. FILE* file = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); @@ -1493,30 +1206,34 @@ mod tests { return 1; } + // Verify that the stdout / stderr worked as expected char* out; - wasi_console_out_read_str(stdout_receiver, &out); + wasi_console_out_read_str(override_stdout_2, &out); + /* assert(strcmp(out, "stdout: hello") == 0); wasi_console_out_delete_str(out); + + char* out2; - wasi_console_out_read_str(stdout_receiver, &out2); + wasi_console_out_read_str(override_stdout_2, &out2); assert(strcmp(out2, "") == 0); wasi_console_out_delete_str(out2); char* out3; - wasi_console_out_read_str(stderr_receiver, &out3); + wasi_console_out_read_str(override_stderr_2, &out3); assert(strcmp(out3, "stderr: hello") == 0); wasi_console_out_delete_str(out3); char* out4; - wasi_console_out_read_str(stderr_receiver, &out4); + wasi_console_out_read_str(override_stderr_2, &out4); assert(strcmp(out4, "") == 0); wasi_console_out_delete_str(out4); + */ - wasi_console_out_delete(stdout_receiver); - wasi_console_out_delete(stderr_receiver); - + wasi_console_out_delete(override_stdout_2); + wasi_console_out_delete(override_stderr_2); wasm_byte_vec_delete(&binary); wasm_module_delete(module); wasm_func_delete(run_func); @@ -1529,6 +1246,4 @@ mod tests { }) .success(); } - */ - } diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 9b2e1a42e9b..4ddd4f3668f 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -177,6 +177,8 @@ impl Read for WasiPipe { let read = reader.read(buf).map(|_| buf_len as usize)?; inner_buf.advance(read); return Ok(read); + } else if buf_len == 0 { + return Ok(0); } } let rx = self.rx.lock().unwrap(); @@ -185,7 +187,9 @@ impl Read for WasiPipe { // Errors can happen if the sender has been dropped already // In this case, just return 0 to indicate that we can't read any // bytes anymore - Err(_) => { return Ok(0); }, + Err(_) => { + return Ok(0); + } }; self.read_buffer.replace(Bytes::from(data)); } From 815da05e43e2eba47da9a178784934d1acedfbe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 6 Sep 2022 20:10:00 +0200 Subject: [PATCH 34/65] Rename wasi_console_out_t to wasi_pipe_t --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 204 +++++++++++++-------------- 1 file changed, 99 insertions(+), 105 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index bbb2630c67f..9cd4d27d8fc 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -51,7 +51,7 @@ pub type WasiConsoleIoEnvDestructor = unsafe extern "C" fn(*const c_void) -> i64 #[allow(clippy::box_collection, clippy::redundant_allocation)] #[repr(C)] #[derive(Clone)] -pub struct wasi_console_out_t { +pub struct wasi_pipe_t { read: WasiConsoleIoReadCallback, write: WasiConsoleIoWriteCallback, seek: WasiConsoleIoSeekCallback, @@ -59,27 +59,27 @@ pub struct wasi_console_out_t { data: Option>>>>, } -impl wasi_console_out_t { +impl wasi_pipe_t { fn get_data_mut(&self, op_id: &'static str) -> io::Result>> { self.data .as_ref() .ok_or_else(|| { io::Error::new( io::ErrorKind::Other, - format!("could not lock mutex ({op_id}) on wasi_console_out_t: no mutex"), + format!("could not lock mutex ({op_id}) on wasi_pipe_t: no mutex"), ) })? .lock() .map_err(|e| { io::Error::new( io::ErrorKind::Other, - format!("could not lock mutex ({op_id}) on wasi_console_out_t: {e}"), + format!("could not lock mutex ({op_id}) on wasi_pipe_t: {e}"), ) }) } } -impl Drop for wasi_console_out_t { +impl Drop for wasi_pipe_t { fn drop(&mut self) { let data = match self.data.take() { Some(s) => s, @@ -104,18 +104,18 @@ impl Drop for wasi_console_out_t { let error = unsafe { (self.destructor)(inner_value.as_mut_ptr() as *const c_void) }; if error < 0 { - println!("error dropping wasi_console_out_t: {error}"); + println!("error dropping wasi_pipe_t: {error}"); } } } -impl fmt::Debug for wasi_console_out_t { +impl fmt::Debug for wasi_pipe_t { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "wasi_console_out_t") + write!(f, "wasi_pipe_t") } } -impl io::Read for wasi_console_out_t { +impl io::Read for wasi_pipe_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { let self_read = self.read; let mut data = self.get_data_mut("read")?; @@ -128,13 +128,13 @@ impl io::Read for wasi_console_out_t { } else { Err(io::Error::new( io::ErrorKind::Other, - format!("could not read from wasi_console_out_t: {result}"), + format!("could not read from wasi_pipe_t: {result}"), )) } } } -impl io::Write for wasi_console_out_t { +impl io::Write for wasi_pipe_t { fn write(&mut self, buf: &[u8]) -> io::Result { let self_write = self.write; let mut data = self.get_data_mut("write")?; @@ -152,7 +152,7 @@ impl io::Write for wasi_console_out_t { Err(std::io::Error::new( std::io::ErrorKind::Other, format!( - "could not write {} bytes to wasi_console_out_t: {result}", + "could not write {} bytes to wasi_pipe_t: {result}", buf.len() ), )) @@ -175,13 +175,13 @@ impl io::Write for wasi_console_out_t { } else { Err(std::io::Error::new( std::io::ErrorKind::Other, - format!("could not flush wasi_console_out_t: {result}"), + format!("could not flush wasi_pipe_t: {result}"), )) } } } -impl io::Seek for wasi_console_out_t { +impl io::Seek for wasi_pipe_t { fn seek(&mut self, pos: SeekFrom) -> io::Result { let self_seek = self.seek; let mut data = self.get_data_mut("seek")?; @@ -196,13 +196,13 @@ impl io::Seek for wasi_console_out_t { } else { Err(std::io::Error::new( std::io::ErrorKind::Other, - format!("could not seek to {pos:?} wasi_console_out_t: {result}"), + format!("could not seek to {pos:?} wasi_pipe_t: {result}"), )) } } } -impl VirtualFile for wasi_console_out_t { +impl VirtualFile for wasi_pipe_t { fn last_accessed(&self) -> u64 { 0 } @@ -225,20 +225,19 @@ impl VirtualFile for wasi_console_out_t { } } -/// Creates a new callback object that is being #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_new( +pub unsafe extern "C" fn wasi_pipe_new_internal( read: WasiConsoleIoReadCallback, write: WasiConsoleIoWriteCallback, seek: WasiConsoleIoSeekCallback, destructor: WasiConsoleIoEnvDestructor, env_data: *const c_void, env_data_len: usize, -) -> *mut wasi_console_out_t { +) -> *mut wasi_pipe_t { let data_vec: Vec = std::slice::from_raw_parts(env_data as *const c_char, env_data_len).to_vec(); - Box::leak(Box::new(wasi_console_out_t { + Box::leak(Box::new(wasi_pipe_t { read, write, seek, @@ -247,26 +246,26 @@ pub unsafe extern "C" fn wasi_console_out_new( })) } -/// Creates a `wasi_console_out_t` callback object that does nothing +/// Creates a `wasi_pipe_t` callback object that does nothing /// and redirects stdout / stderr to /dev/null #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_new_null() -> *mut wasi_console_out_t { +pub unsafe extern "C" fn wasi_pipe_new_null() -> *mut wasi_pipe_t { let mut data = Vec::new(); - wasi_console_out_new( - wasi_console_out_read_null, - wasi_console_out_write_null, - wasi_console_out_seek_null, - wasi_console_out_delete_null, + wasi_pipe_new_internal( + wasi_pipe_read_null, + wasi_pipe_write_null, + wasi_pipe_seek_null, + wasi_pipe_delete_null, data.as_mut_ptr(), data.len(), ) } -extern "C" fn wasi_console_out_read_null(_: *const c_void, _: *mut c_char, _: usize) -> i64 { +extern "C" fn wasi_pipe_read_null(_: *const c_void, _: *mut c_char, _: usize) -> i64 { 0 } -extern "C" fn wasi_console_out_write_null( +extern "C" fn wasi_pipe_write_null( _: *const c_void, _: *const c_char, _: usize, @@ -275,15 +274,15 @@ extern "C" fn wasi_console_out_write_null( 0 } -extern "C" fn wasi_console_out_seek_null(_: *const c_void, _: c_char, _: i64) -> i64 { +extern "C" fn wasi_pipe_seek_null(_: *const c_void, _: c_char, _: i64) -> i64 { 0 } -extern "C" fn wasi_console_out_delete_null(_: *const c_void) -> i64 { +extern "C" fn wasi_pipe_delete_null(_: *const c_void) -> i64 { 0 } -unsafe extern "C" fn wasi_console_out_read_memory_2( +unsafe extern "C" fn wasi_pipe_read_memory_2( ptr: *const c_void, /* = *WasiPipe */ byte_ptr: *mut c_char, /* &[u8] bytes to read */ max_bytes: usize, /* max bytes to read */ @@ -299,7 +298,7 @@ unsafe extern "C" fn wasi_console_out_read_memory_2( r } -unsafe extern "C" fn wasi_console_out_write_memory_2( +unsafe extern "C" fn wasi_pipe_write_memory_2( ptr: *const c_void, /* = *WasiPipe */ byte_ptr: *const c_char, byte_len: usize, @@ -324,7 +323,7 @@ unsafe extern "C" fn wasi_console_out_write_memory_2( } } -unsafe extern "C" fn wasi_console_out_seek_memory_2( +unsafe extern "C" fn wasi_pipe_seek_memory_2( ptr: *const c_void, /* = *WasiPipe */ direction: c_char, seek_to: i64, @@ -350,7 +349,7 @@ unsafe extern "C" fn wasi_console_out_seek_memory_2( } #[no_mangle] -unsafe extern "C" fn wasi_console_out_delete_memory_2( +unsafe extern "C" fn wasi_pipe_delete_memory_2( ptr: *const c_void, /* = *WasiPipe */ ) -> i64 { let ptr = ptr as *const WasiPipe; @@ -359,12 +358,12 @@ unsafe extern "C" fn wasi_console_out_delete_memory_2( 0 } -/// Creates a new `wasi_console_out_t` which uses a memory buffer +/// Creates a new `wasi_pipe_t` which uses a memory buffer /// for backing stdin / stdout / stderr #[no_mangle] pub unsafe extern "C" fn wasi_pipe_new( - ptr_user: &mut *mut wasi_console_out_t, -) -> *mut wasi_console_out_t { + ptr_user: &mut *mut wasi_pipe_t, +) -> *mut wasi_pipe_t { use std::mem::ManuallyDrop; let pair = WasiPipe::new(); @@ -372,36 +371,36 @@ pub unsafe extern "C" fn wasi_pipe_new( let mut data1 = ManuallyDrop::new(pair.send); let ptr1: &mut WasiPipe = &mut data1; - *ptr_user = wasi_console_out_new( - wasi_console_out_read_memory_2, - wasi_console_out_write_memory_2, - wasi_console_out_seek_memory_2, - wasi_console_out_delete_memory_2, + *ptr_user = wasi_pipe_new_internal( + wasi_pipe_read_memory_2, + wasi_pipe_write_memory_2, + wasi_pipe_seek_memory_2, + wasi_pipe_delete_memory_2, ptr1 as *mut _ as *mut c_void, std::mem::size_of::(), ); let mut data2 = ManuallyDrop::new(pair.recv); let ptr2: &mut WasiPipe = &mut data2; - wasi_console_out_new( - wasi_console_out_read_memory_2, - wasi_console_out_write_memory_2, - wasi_console_out_seek_memory_2, - wasi_console_out_delete_memory_2, + wasi_pipe_new_internal( + wasi_pipe_read_memory_2, + wasi_pipe_write_memory_2, + wasi_pipe_seek_memory_2, + wasi_pipe_delete_memory_2, ptr2 as *mut _ as *mut c_void, std::mem::size_of::(), ) } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_delete(ptr: *mut wasi_console_out_t) -> bool { +pub unsafe extern "C" fn wasi_pipe_delete(ptr: *mut wasi_pipe_t) -> bool { let _ = Box::from_raw(ptr); true } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_write_bytes( - ptr: *mut wasi_console_out_t, +pub unsafe extern "C" fn wasi_pipe_write_bytes( + ptr: *mut wasi_pipe_t, buf: *const c_char, len: usize, ) -> i64 { @@ -416,14 +415,14 @@ pub unsafe extern "C" fn wasi_console_out_write_bytes( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_write_str( - ptr: *const wasi_console_out_t, +pub unsafe extern "C" fn wasi_pipe_write_str( + ptr: *const wasi_pipe_t, buf: *const c_char, ) -> i64 { use std::io::Write; let c_str = std::ffi::CStr::from_ptr(buf); let as_bytes_with_nul = c_str.to_bytes(); - let ptr = &mut *(ptr as *mut wasi_console_out_t); + let ptr = &mut *(ptr as *mut wasi_pipe_t); match ptr.write(as_bytes_with_nul) { Ok(o) => o as i64, Err(_) => -1, @@ -431,7 +430,7 @@ pub unsafe extern "C" fn wasi_console_out_write_str( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_flush(ptr: *mut wasi_console_out_t) -> i64 { +pub unsafe extern "C" fn wasi_pipe_flush(ptr: *mut wasi_pipe_t) -> i64 { use std::io::Write; let ptr = &mut *ptr; match ptr.flush() { @@ -441,13 +440,13 @@ pub unsafe extern "C" fn wasi_console_out_flush(ptr: *mut wasi_console_out_t) -> } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_read_bytes( - ptr: *const wasi_console_out_t, +pub unsafe extern "C" fn wasi_pipe_read_bytes( + ptr: *const wasi_pipe_t, buf: *const c_char, read: usize, ) -> i64 { use std::io::Read; - let ptr = &mut *(ptr as *mut wasi_console_out_t); + let ptr = &mut *(ptr as *mut wasi_pipe_t); let buf = buf as *mut u8; let slice = std::slice::from_raw_parts_mut(buf, read); match ptr.read(slice) { @@ -457,14 +456,14 @@ pub unsafe extern "C" fn wasi_console_out_read_bytes( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_delete_str(buf: *mut c_char) { +pub unsafe extern "C" fn wasi_pipe_delete_str(buf: *mut c_char) { use std::ffi::CString; let _ = CString::from_raw(buf); } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_read_str( - ptr: *const wasi_console_out_t, +pub unsafe extern "C" fn wasi_pipe_read_str( + ptr: *const wasi_pipe_t, buf: *mut *mut c_char, ) -> i64 { use std::ffi::CString; @@ -473,7 +472,7 @@ pub unsafe extern "C" fn wasi_console_out_read_str( const BLOCK_SIZE: usize = 1024; let mut target = Vec::new(); - let ptr = &mut *(ptr as *mut wasi_console_out_t); + let ptr = &mut *(ptr as *mut wasi_pipe_t); loop { let mut v = vec![0; BLOCK_SIZE]; @@ -505,8 +504,8 @@ pub unsafe extern "C" fn wasi_console_out_read_str( } #[no_mangle] -pub unsafe extern "C" fn wasi_console_out_seek( - ptr: *mut wasi_console_out_t, +pub unsafe extern "C" fn wasi_pipe_seek( + ptr: *mut wasi_pipe_t, // 0 = from start // 1 = from end // 2 = from current position @@ -535,9 +534,9 @@ pub unsafe extern "C" fn wasi_console_out_seek( #[derive(Debug)] #[allow(non_camel_case_types)] pub struct wasi_config_t { - inherit_stdout: Option>, - inherit_stderr: Option>, - inherit_stdin: Option>, + inherit_stdout: Option>, + inherit_stderr: Option>, + inherit_stdin: Option>, state_builder: WasiStateBuilder, } @@ -644,7 +643,7 @@ pub unsafe extern "C" fn wasi_config_mapdir( #[no_mangle] pub extern "C" fn wasi_config_capture_stdout(config: &mut wasi_config_t) { - config.inherit_stdout = Some(unsafe { Box::from_raw(wasi_console_out_new_null()) }); + config.inherit_stdout = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] @@ -654,7 +653,7 @@ pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { #[no_mangle] pub extern "C" fn wasi_config_capture_stderr(config: &mut wasi_config_t) { - config.inherit_stderr = Some(unsafe { Box::from_raw(wasi_console_out_new_null()) }); + config.inherit_stderr = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] @@ -664,7 +663,7 @@ pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { #[no_mangle] pub extern "C" fn wasi_config_capture_stdin(config: &mut wasi_config_t) { - config.inherit_stdin = Some(unsafe { Box::from_raw(wasi_console_out_new_null()) }); + config.inherit_stdin = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] @@ -675,7 +674,7 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdin( config: &mut wasi_config_t, - stdin: *mut wasi_console_out_t, + stdin: *mut wasi_pipe_t, ) { config.state_builder.stdin(Box::from_raw(stdin)); } @@ -683,7 +682,7 @@ pub unsafe extern "C" fn wasi_config_overwrite_stdin( #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdout( config: &mut wasi_config_t, - stdout: *mut wasi_console_out_t, + stdout: *mut wasi_pipe_t, ) { config.state_builder.stdout(Box::from_raw(stdout)); } @@ -691,7 +690,7 @@ pub unsafe extern "C" fn wasi_config_overwrite_stdout( #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stderr( config: &mut wasi_config_t, - stderr: *mut wasi_console_out_t, + stderr: *mut wasi_pipe_t, ) { config.state_builder.stderr(Box::from_raw(stderr)); } @@ -1053,24 +1052,24 @@ mod tests { #include "stdio.h" int main() { - wasi_console_out_t* override_stdout_1 = NULL; - wasi_console_out_t* override_stdout_2 = wasi_pipe_new(&override_stdout_1); + wasi_pipe_t* override_stdout_1 = NULL; + wasi_pipe_t* override_stdout_2 = wasi_pipe_new(&override_stdout_1); assert(override_stdout_1); assert(override_stdout_2); // write to override_stdout_1, then close override_stdout_1 - wasi_console_out_write_str(override_stdout_1, "test"); - wasi_console_out_delete(override_stdout_1); + wasi_pipe_write_str(override_stdout_1, "test"); + wasi_pipe_delete(override_stdout_1); // read from override_stdout_2, after override_stdout_1 has been closed so it doesn't block char* out; - wasi_console_out_read_str(override_stdout_2, &out); + wasi_pipe_read_str(override_stdout_2, &out); assert(strcmp(out, "test") == 0); - wasi_console_out_delete_str(out); + wasi_pipe_delete_str(out); // cleanup - wasi_console_out_delete(override_stdout_2); + wasi_pipe_delete(override_stdout_2); return 0; } }) @@ -1090,18 +1089,18 @@ mod tests { wasm_store_t* store = wasm_store_new(engine); wasi_config_t* config = wasi_config_new("example_program"); - wasi_console_out_t* override_stdout_1 = NULL; - wasi_console_out_t* override_stdout_2 = wasi_pipe_new(&override_stdout_1); + wasi_pipe_t* override_stdout_1 = NULL; + wasi_pipe_t* override_stdout_2 = wasi_pipe_new(&override_stdout_1); assert(override_stdout_1); assert(override_stdout_2); - wasi_console_out_t* override_stderr_1 = NULL; - wasi_console_out_t* override_stderr_2 = wasi_pipe_new(&override_stderr_1); + wasi_pipe_t* override_stderr_1 = NULL; + wasi_pipe_t* override_stderr_2 = wasi_pipe_new(&override_stderr_1); assert(override_stderr_1); assert(override_stderr_2); - wasi_console_out_t* override_stdin_1 = NULL; - wasi_console_out_t* override_stdin_2 = wasi_pipe_new(&override_stdin_1); + wasi_pipe_t* override_stdin_1 = NULL; + wasi_pipe_t* override_stdin_2 = wasi_pipe_new(&override_stdin_1); assert(override_stdin_1); assert(override_stdin_2); @@ -1110,10 +1109,10 @@ mod tests { wasi_config_overwrite_stdout(config, override_stdout_1); wasi_config_overwrite_stderr(config, override_stderr_1); - // write to stdin, then close all senders in order not to block - // during execution - wasi_console_out_write_str(override_stdin_2, "hello"); - wasi_console_out_delete(override_stdin_2); + // write to stdin, then close all senders in order + // not to block during execution + wasi_pipe_write_str(override_stdin_2, "hello"); + wasi_pipe_delete(override_stdin_2); // Load binary. FILE* file = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); @@ -1206,34 +1205,29 @@ mod tests { return 1; } - // Verify that the stdout / stderr worked as expected char* out; - wasi_console_out_read_str(override_stdout_2, &out); - /* + wasi_pipe_read_str(override_stdout_2, &out); assert(strcmp(out, "stdout: hello") == 0); - wasi_console_out_delete_str(out); - - + wasi_pipe_delete_str(out); char* out2; - wasi_console_out_read_str(override_stdout_2, &out2); + wasi_pipe_read_str(override_stdout_2, &out2); assert(strcmp(out2, "") == 0); - wasi_console_out_delete_str(out2); + wasi_pipe_delete_str(out2); char* out3; - wasi_console_out_read_str(override_stderr_2, &out3); + wasi_pipe_read_str(override_stderr_2, &out3); assert(strcmp(out3, "stderr: hello") == 0); - wasi_console_out_delete_str(out3); + wasi_pipe_delete_str(out3); char* out4; - wasi_console_out_read_str(override_stderr_2, &out4); + wasi_pipe_read_str(override_stderr_2, &out4); assert(strcmp(out4, "") == 0); - wasi_console_out_delete_str(out4); - */ + wasi_pipe_delete_str(out4); - wasi_console_out_delete(override_stdout_2); - wasi_console_out_delete(override_stderr_2); + wasi_pipe_delete(override_stdout_2); + wasi_pipe_delete(override_stderr_2); wasm_byte_vec_delete(&binary); wasm_module_delete(module); wasm_func_delete(run_func); From 1f4c46bf58045c85d11832e1eebb9b987a31dfcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Wed, 7 Sep 2022 17:50:17 +0200 Subject: [PATCH 35/65] Fix stdio tests for WasiPipe (currently still failing) --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 27 ++++++------------------- lib/wasi/tests/stdio.rs | 30 +++++++++++++++------------- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 9cd4d27d8fc..f2168ffbe18 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -265,12 +265,7 @@ extern "C" fn wasi_pipe_read_null(_: *const c_void, _: *mut c_char, _: usize) -> 0 } -extern "C" fn wasi_pipe_write_null( - _: *const c_void, - _: *const c_char, - _: usize, - _: bool, -) -> i64 { +extern "C" fn wasi_pipe_write_null(_: *const c_void, _: *const c_char, _: usize, _: bool) -> i64 { 0 } @@ -349,9 +344,7 @@ unsafe extern "C" fn wasi_pipe_seek_memory_2( } #[no_mangle] -unsafe extern "C" fn wasi_pipe_delete_memory_2( - ptr: *const c_void, /* = *WasiPipe */ -) -> i64 { +unsafe extern "C" fn wasi_pipe_delete_memory_2(ptr: *const c_void /* = *WasiPipe */) -> i64 { let ptr = ptr as *const WasiPipe; let mut pipe: WasiPipe = std::mem::transmute_copy(&*ptr); // dropped here, destructors run here pipe.close(); @@ -361,9 +354,7 @@ unsafe extern "C" fn wasi_pipe_delete_memory_2( /// Creates a new `wasi_pipe_t` which uses a memory buffer /// for backing stdin / stdout / stderr #[no_mangle] -pub unsafe extern "C" fn wasi_pipe_new( - ptr_user: &mut *mut wasi_pipe_t, -) -> *mut wasi_pipe_t { +pub unsafe extern "C" fn wasi_pipe_new(ptr_user: &mut *mut wasi_pipe_t) -> *mut wasi_pipe_t { use std::mem::ManuallyDrop; let pair = WasiPipe::new(); @@ -415,10 +406,7 @@ pub unsafe extern "C" fn wasi_pipe_write_bytes( } #[no_mangle] -pub unsafe extern "C" fn wasi_pipe_write_str( - ptr: *const wasi_pipe_t, - buf: *const c_char, -) -> i64 { +pub unsafe extern "C" fn wasi_pipe_write_str(ptr: *const wasi_pipe_t, buf: *const c_char) -> i64 { use std::io::Write; let c_str = std::ffi::CStr::from_ptr(buf); let as_bytes_with_nul = c_str.to_bytes(); @@ -462,10 +450,7 @@ pub unsafe extern "C" fn wasi_pipe_delete_str(buf: *mut c_char) { } #[no_mangle] -pub unsafe extern "C" fn wasi_pipe_read_str( - ptr: *const wasi_pipe_t, - buf: *mut *mut c_char, -) -> i64 { +pub unsafe extern "C" fn wasi_pipe_read_str(ptr: *const wasi_pipe_t, buf: *mut *mut c_char) -> i64 { use std::ffi::CString; use std::io::Read; @@ -1109,7 +1094,7 @@ mod tests { wasi_config_overwrite_stdout(config, override_stdout_1); wasi_config_overwrite_stderr(config, override_stderr_1); - // write to stdin, then close all senders in order + // write to stdin, then close all senders in order // not to block during execution wasi_pipe_write_str(override_stdin_2, "hello"); wasi_pipe_delete(override_stdin_2); diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 78b93520e1a..7bd26acb781 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -1,7 +1,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; -use wasmer_wasi::{Pipe, WasiState}; +use wasmer_wasi::{WasiPipe, WasiState, WasiPipePair}; mod sys { #[test] @@ -73,10 +73,10 @@ fn test_stdout() { "#).unwrap(); // Create the `WasiEnv`. - let mut stdout = Pipe::default(); + let WasiPipePair { send, mut recv } = WasiPipe::new(); let wasi_env = WasiState::new("command-name") .args(&["Gordon"]) - .stdout(Box::new(stdout.clone())) + .stdout(Box::new(send)) .finalize(&mut store) .unwrap(); @@ -93,7 +93,7 @@ fn test_stdout() { start.call(&mut store, &[]).unwrap(); let mut stdout_str = String::new(); - stdout.read_to_string(&mut stdout_str).unwrap(); + recv.read_to_string(&mut stdout_str).unwrap(); let stdout_as_str = stdout_str.as_str(); assert_eq!(stdout_as_str, "hello world\n"); } @@ -110,7 +110,7 @@ fn test_env() { }); // Create the `WasiEnv`. - let mut stdout = Pipe::new(); + let WasiPipePair { send, mut recv } = WasiPipe::new(); let mut wasi_state_builder = WasiState::new("command-name"); wasi_state_builder .args(&["Gordon"]) @@ -119,7 +119,7 @@ fn test_env() { .env("TEST2", "VALUE2"); // panic!("envs: {:?}", wasi_state_builder.envs); let wasi_env = wasi_state_builder - .stdout(Box::new(stdout.clone())) + .stdout(Box::new(send)) .finalize(&mut store) .unwrap(); @@ -136,7 +136,7 @@ fn test_env() { start.call(&mut store, &[]).unwrap(); let mut stdout_str = String::new(); - stdout.read_to_string(&mut stdout_str).unwrap(); + recv.read_to_string(&mut stdout_str).unwrap(); let stdout_as_str = stdout_str.as_str(); assert_eq!(stdout_as_str, "Env vars:\nDOG=X\nTEST2=VALUE2\nTEST=VALUE\nDOG Ok(\"X\")\nDOG_TYPE Err(NotPresent)\nSET VAR Ok(\"HELLO\")\n"); } @@ -146,15 +146,17 @@ fn test_stdin() { let module = Module::new(&store, include_bytes!("stdin-hello.wasm")).unwrap(); // Create the `WasiEnv`. - let mut stdin = Pipe::new(); - let wasi_env = WasiState::new("command-name") - .stdin(Box::new(stdin.clone())) - .finalize(&mut store) - .unwrap(); + let WasiPipePair { mut send, mut recv } = WasiPipe::new(); // Write to STDIN let buf = "Hello, stdin!\n".as_bytes().to_owned(); - stdin.write(&buf[..]).unwrap(); + send.write(&buf[..]).unwrap(); + send.close(); + + let wasi_env = WasiState::new("command-name") + .stdin(Box::new(send)) + .finalize(&mut store) + .unwrap(); // Generate an `ImportObject`. let import_object = wasi_env.import_object(&mut store, &module).unwrap(); @@ -171,6 +173,6 @@ fn test_stdin() { // We assure stdin is now empty let mut buf = Vec::new(); - stdin.read_to_end(&mut buf).unwrap(); + recv.read_to_end(&mut buf).unwrap(); assert_eq!(buf.len(), 0); } From d840b5c5f6e6bc538b5c6438fb060be54085fd33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Wed, 7 Sep 2022 18:41:06 +0200 Subject: [PATCH 36/65] Fix unit test with proper compiled .wasm file --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 19 +++++++++++++++++- .../tests/wasm-c-api/example/testrust.wasm | Bin 0 -> 70088 bytes 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100755 lib/c-api/tests/wasm-c-api/example/testrust.wasm diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index f2168ffbe18..a7d0af5c84f 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -1099,8 +1099,25 @@ mod tests { wasi_pipe_write_str(override_stdin_2, "hello"); wasi_pipe_delete(override_stdin_2); + /* + // testrust.wasm: + + use std::io::{self, Write}; + + fn main() -> io::Result<()> { + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + + io::stdout().write_all(format!("stdout: {input}").as_bytes())?; + io::stderr().write_all(format!("stderr: {input}").as_bytes())?; + + Ok(()) + } + */ + // Load binary. - FILE* file = fopen("tests/wasm-c-api/example/stdio.wasm", "rb"); + FILE* file = fopen("tests/wasm-c-api/example/testrust.wasm", "rb"); if (!file) { printf("> Error loading module!\n"); return 1; diff --git a/lib/c-api/tests/wasm-c-api/example/testrust.wasm b/lib/c-api/tests/wasm-c-api/example/testrust.wasm new file mode 100755 index 0000000000000000000000000000000000000000..92a691fc6bb65016f2560464b2863c2a07b60967 GIT binary patch literal 70088 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

R%{_%tN1nA@;}Vf1$_-{lmr9u#McP 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 Date: Fri, 9 Sep 2022 13:27:46 +0200 Subject: [PATCH 37/65] "Fix" WasiPipe to allow multiple-write-single-read buffers --- lib/wasi/src/state/pipe.rs | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 4ddd4f3668f..05e392f6b9d 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -173,22 +173,45 @@ impl Read for WasiPipe { if let Some(inner_buf) = self.read_buffer.as_mut() { let buf_len = inner_buf.len(); if buf_len > 0 { - let mut reader = inner_buf.as_ref(); - let read = reader.read(buf).map(|_| buf_len as usize)?; - inner_buf.advance(read); - return Ok(read); - } else if buf_len == 0 { + if inner_buf.len() > buf.len() { + let mut reader = inner_buf.as_ref(); + let read = reader.read_exact(buf).map(|_| buf.len())?; + inner_buf.advance(read); + return Ok(read); + } else { + let mut reader = inner_buf.as_ref(); + let read = reader.read(buf).map(|_| buf_len as usize)?; + inner_buf.advance(read); + return Ok(read); + } + } else { return Ok(0); } } let rx = self.rx.lock().unwrap(); - let data = match rx.recv() { - Ok(o) => o, - // Errors can happen if the sender has been dropped already - // In this case, just return 0 to indicate that we can't read any - // bytes anymore + + // We need to figure out whether we need to block here. + // The problem is that in cases of multiple buffered reads like: + // + // println!("abc"); + // println!("def"); + + let data = match rx.try_recv() { + Ok(mut s) => { + s.append(&mut rx.try_iter().flat_map(|f| f.into_iter()).collect()); + s + }, Err(_) => { - return Ok(0); + // could not immediately receive bytes, so we need to block + match rx.recv() { + Ok(o) => o, + // Errors can happen if the sender has been dropped already + // In this case, just return 0 to indicate that we can't read any + // bytes anymore + Err(_) => { + return Ok(0); + } + } } }; self.read_buffer.replace(Bytes::from(data)); From 6b6785ba69b96121fd934898bdd2b23d078a1855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 9 Sep 2022 13:51:20 +0200 Subject: [PATCH 38/65] Fix "make lint" --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 13 ++++++------- lib/wasi/src/state/pipe.rs | 14 +++++++++++--- lib/wasi/src/state/types.rs | 7 +------ lib/wasi/src/syscalls/mod.rs | 4 ++-- lib/wasi/tests/stdio.rs | 8 ++++---- tests/lib/wast/src/wasi_wast.rs | 4 ++-- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index a7d0af5c84f..845a506583d 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -23,8 +23,8 @@ use std::{ sync::MutexGuard, }; use wasmer_wasi::{ - get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiState, - WasiStateBuilder, WasiVersion, + get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiPipePair, + WasiState, WasiStateBuilder, WasiVersion, }; /// Function callback that takes: @@ -286,11 +286,10 @@ unsafe extern "C" fn wasi_pipe_read_memory_2( let ptr = ptr as *mut WasiPipe; let ptr = &mut *ptr; let slice = std::slice::from_raw_parts_mut(byte_ptr as *mut u8, max_bytes); - let r = match ptr.read(slice) { + match ptr.read(slice) { Ok(o) => o as i64, Err(_) => -1, - }; - r + } } unsafe extern "C" fn wasi_pipe_write_memory_2( @@ -357,7 +356,7 @@ unsafe extern "C" fn wasi_pipe_delete_memory_2(ptr: *const c_void /* = *WasiPipe pub unsafe extern "C" fn wasi_pipe_new(ptr_user: &mut *mut wasi_pipe_t) -> *mut wasi_pipe_t { use std::mem::ManuallyDrop; - let pair = WasiPipe::new(); + let pair = WasiPipePair::new(); let mut data1 = ManuallyDrop::new(pair.send); let ptr1: &mut WasiPipe = &mut data1; @@ -1115,7 +1114,7 @@ mod tests { Ok(()) } */ - + // Load binary. FILE* file = fopen("tests/wasm-c-api/example/testrust.wasm", "rb"); if (!file) { diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 05e392f6b9d..68b17543e1b 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -71,7 +71,13 @@ impl VirtualFile for WasiPipePair { } } -impl WasiPipe { +impl Default for WasiPipePair { + fn default() -> Self { + Self::new() + } +} + +impl WasiPipePair { pub fn new() -> WasiPipePair { let (tx1, rx1) = mpsc::channel(); let (tx2, rx2) = mpsc::channel(); @@ -93,7 +99,9 @@ impl WasiPipe { recv: pipe2, } } +} +impl WasiPipe { pub fn recv( &mut self, memory: &MemoryView, @@ -189,7 +197,7 @@ impl Read for WasiPipe { } } let rx = self.rx.lock().unwrap(); - + // We need to figure out whether we need to block here. // The problem is that in cases of multiple buffered reads like: // @@ -200,7 +208,7 @@ impl Read for WasiPipe { Ok(mut s) => { s.append(&mut rx.try_iter().flat_map(|f| f.into_iter()).collect()); s - }, + } Err(_) => { // could not immediately receive bytes, so we need to block match rx.recv() { diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 671f58dd03f..7cc78c4a411 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -4,12 +4,7 @@ use crate::syscalls::types::*; use serde::{Deserialize, Serialize}; #[cfg(all(unix, feature = "sys-poll"))] use std::convert::TryInto; -use std::{ - collections::VecDeque, - io::{self, Read, Seek, Write}, - sync::{Arc, Mutex}, - time::Duration, -}; +use std::time::Duration; use wasmer_vbus::BusError; #[cfg(feature = "host-fs")] diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index ce630cdac4e..5725714f59b 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -32,7 +32,7 @@ use crate::{ state::{ self, fs_error_into_wasi_err, iterate_poll_events, net_error_into_wasi_err, poll, virtual_file_type_to_wasi_file_type, Fd, Inode, InodeSocket, InodeSocketKind, InodeVal, - Kind, PollEvent, PollEventBuilder, WasiPipe, WasiState, MAX_SYMLINKS, + Kind, PollEvent, PollEventBuilder, WasiPipePair, WasiState, MAX_SYMLINKS, }, WasiEnv, WasiError, WasiThread, WasiThreadId, }; @@ -1807,7 +1807,7 @@ pub fn fd_pipe( let env = ctx.data(); let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); - let pipes = WasiPipe::new(); + let pipes = WasiPipePair::new(); let pipe1 = pipes.send; let pipe2 = pipes.recv; diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 7bd26acb781..62f83eae18e 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -1,7 +1,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; -use wasmer_wasi::{WasiPipe, WasiState, WasiPipePair}; +use wasmer_wasi::{WasiPipe, WasiPipePair, WasiState}; mod sys { #[test] @@ -73,7 +73,7 @@ fn test_stdout() { "#).unwrap(); // Create the `WasiEnv`. - let WasiPipePair { send, mut recv } = WasiPipe::new(); + let WasiPipePair { send, mut recv } = WasiPipePair::new(); let wasi_env = WasiState::new("command-name") .args(&["Gordon"]) .stdout(Box::new(send)) @@ -110,7 +110,7 @@ fn test_env() { }); // Create the `WasiEnv`. - let WasiPipePair { send, mut recv } = WasiPipe::new(); + let WasiPipePair { send, mut recv } = WasiPipePair::new(); let mut wasi_state_builder = WasiState::new("command-name"); wasi_state_builder .args(&["Gordon"]) @@ -146,7 +146,7 @@ fn test_stdin() { let module = Module::new(&store, include_bytes!("stdin-hello.wasm")).unwrap(); // Create the `WasiEnv`. - let WasiPipePair { mut send, mut recv } = WasiPipe::new(); + let WasiPipePair { mut send, mut recv } = WasiPipePair::new(); // Write to STDIN let buf = "Hello, stdin!\n".as_bytes().to_owned(); diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index f899402e83d..79a26d50219 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -9,7 +9,7 @@ use wasmer_vfs::{host_fs, mem_fs, FileSystem}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; use wasmer_wasi::{ generate_import_object_from_env, get_wasi_version, FsError, VirtualFile, WasiEnv, - WasiFunctionEnv, WasiPipe, WasiState, WasiVersion, + WasiFunctionEnv, WasiPipePair, WasiState, WasiVersion, }; use wast::parser::{self, Parse, ParseBuffer, Parser}; @@ -143,7 +143,7 @@ impl<'a> WasiTest<'a> { )> { let mut builder = WasiState::new(self.wasm_path); - let stdin_pipe = WasiPipe::new(); + let stdin_pipe = WasiPipePair::new(); builder.stdin(Box::new(stdin_pipe)); for (name, value) in &self.envs { From c4a16ae68285d7a7bcb28028e739083d34c1f463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 9 Sep 2022 15:31:57 +0200 Subject: [PATCH 39/65] Fix WasiPipe + examples --- examples/wasi_pipes.rs | 6 +-- lib/wasi/src/state/pipe.rs | 83 +++++++++++++++++++++++++++++++++++++- lib/wasi/tests/stdio.rs | 9 ++--- 3 files changed, 89 insertions(+), 9 deletions(-) diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index ed7ef03a075..af78daae4e0 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -14,7 +14,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; -use wasmer_wasi::{Pipe, WasiState}; +use wasmer_wasi::{WasiPipePair, WasiState}; fn main() -> Result<(), Box> { let wasm_path = concat!( @@ -36,8 +36,8 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` with the stdio pipes - let mut input = Pipe::new(); - let mut output = Pipe::new(); + let mut input = WasiPipePair::new_arc(); + let mut output = WasiPipePair::new_arc(); let wasi_env = WasiState::new("hello") .stdin(Box::new(input.clone())) .stdout(Box::new(output.clone())) diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 68b17543e1b..4672409af41 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -5,6 +5,7 @@ use std::convert::TryInto; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::ops::DerefMut; use std::sync::mpsc; +use std::sync::Arc; use std::sync::Mutex; use wasmer::WasmSlice; use wasmer::{MemorySize, MemoryView}; @@ -20,6 +21,7 @@ pub struct WasiPipe { read_buffer: Option, } +/// Pipe pair of (a, b) WasiPipes that are connected together #[derive(Debug)] pub struct WasiPipePair { pub send: WasiPipe, @@ -99,6 +101,82 @@ impl WasiPipePair { recv: pipe2, } } + + pub fn new_arc() -> WasiSharedPipePair { + WasiSharedPipePair { + inner: Arc::new(Mutex::new(Self::new())), + } + } +} + +/// Shared version of WasiPipePair for situations where you need +/// to emulate the old behaviour of `Pipe` (both send and recv on one channel). +#[derive(Debug, Clone)] +pub struct WasiSharedPipePair { + inner: Arc>, +} + +impl Write for WasiSharedPipePair { + fn write(&mut self, buf: &[u8]) -> io::Result { + match self.inner.lock().as_mut().map(|l| l.write(buf)) { + Ok(r) => r, + Err(_) => Ok(0), + } + } + fn flush(&mut self) -> io::Result<()> { + match self.inner.lock().as_mut().map(|l| l.flush()) { + Ok(r) => r, + Err(_) => Ok(()), + } + } +} + +impl Seek for WasiSharedPipePair { + fn seek(&mut self, _: SeekFrom) -> io::Result { + Ok(0) + } +} + +impl Read for WasiSharedPipePair { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + match self.inner.lock().as_mut().map(|l| l.read(buf)) { + Ok(r) => r, + Err(_) => Ok(0), + } + } +} + +impl VirtualFile for WasiSharedPipePair { + fn last_accessed(&self) -> u64 { + self.inner.lock().map(|l| l.last_accessed()).unwrap_or(0) + } + fn last_modified(&self) -> u64 { + self.inner.lock().map(|l| l.last_modified()).unwrap_or(0) + } + fn created_time(&self) -> u64 { + self.inner.lock().map(|l| l.created_time()).unwrap_or(0) + } + fn size(&self) -> u64 { + self.inner.lock().map(|l| l.size()).unwrap_or(0) + } + fn set_len(&mut self, i: u64) -> Result<(), FsError> { + match self.inner.lock().as_mut().map(|l| l.set_len(i)) { + Ok(r) => r, + Err(_) => Err(FsError::Lock), + } + } + fn unlink(&mut self) -> Result<(), FsError> { + match self.inner.lock().as_mut().map(|l| l.unlink()) { + Ok(r) => r, + Err(_) => Err(FsError::Lock), + } + } + fn bytes_available_read(&self) -> Result, FsError> { + self.inner + .lock() + .map(|l| l.bytes_available_read()) + .unwrap_or(Ok(None)) + } } impl WasiPipe { @@ -203,6 +281,8 @@ impl Read for WasiPipe { // // println!("abc"); // println!("def"); + // + // get_stdout() // would only return "abc\n" instead of "abc\ndef\n" let data = match rx.try_recv() { Ok(mut s) => { @@ -216,7 +296,8 @@ impl Read for WasiPipe { // Errors can happen if the sender has been dropped already // In this case, just return 0 to indicate that we can't read any // bytes anymore - Err(_) => { + Err(e) => { + eprintln!("WasiPipe read error: {e}"); return Ok(0); } } diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 62f83eae18e..07ae9dc0206 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -146,15 +146,14 @@ fn test_stdin() { let module = Module::new(&store, include_bytes!("stdin-hello.wasm")).unwrap(); // Create the `WasiEnv`. - let WasiPipePair { mut send, mut recv } = WasiPipePair::new(); + let mut pipe = WasiPipePair::new_arc(); // Write to STDIN let buf = "Hello, stdin!\n".as_bytes().to_owned(); - send.write(&buf[..]).unwrap(); - send.close(); + pipe.write(&buf[..]).unwrap(); let wasi_env = WasiState::new("command-name") - .stdin(Box::new(send)) + .stdin(Box::new(pipe.clone())) .finalize(&mut store) .unwrap(); @@ -173,6 +172,6 @@ fn test_stdin() { // We assure stdin is now empty let mut buf = Vec::new(); - recv.read_to_end(&mut buf).unwrap(); + pipe.read_to_end(&mut buf).unwrap(); assert_eq!(buf.len(), 0); } From 2484db994359d048bfd872fa2c0d362a56f7d9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 10:54:12 +0200 Subject: [PATCH 40/65] Address review comments to prevent leak with Arc::try_unwrap --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 68 +++++++++++----------------- 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 845a506583d..a6fee8d28a8 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -55,12 +55,28 @@ pub struct wasi_pipe_t { read: WasiConsoleIoReadCallback, write: WasiConsoleIoWriteCallback, seek: WasiConsoleIoSeekCallback, + data: Option>>>, +} + +struct WasiPipeDataWithDestructor { + data: Vec, destructor: WasiConsoleIoEnvDestructor, - data: Option>>>>, +} + +impl Drop for WasiPipeDataWithDestructor { + fn drop(&mut self) { + let error = unsafe { (self.destructor)(self.data.as_mut_ptr() as *const c_void) }; + if error < 0 { + panic!("error dropping wasi_pipe_t: {}", error); + } + } } impl wasi_pipe_t { - fn get_data_mut(&self, op_id: &'static str) -> io::Result>> { + fn get_data_mut( + &self, + op_id: &'static str, + ) -> io::Result> { self.data .as_ref() .ok_or_else(|| { @@ -79,36 +95,6 @@ impl wasi_pipe_t { } } -impl Drop for wasi_pipe_t { - fn drop(&mut self) { - let data = match self.data.take() { - Some(s) => s, - None => { - return; - } - }; - - let value = match Arc::try_unwrap(*data) { - Ok(o) => o, - Err(_) => { - return; - } - }; - - let mut inner_value = match value.into_inner() { - Ok(o) => o, - Err(_) => { - return; - } - }; - - let error = unsafe { (self.destructor)(inner_value.as_mut_ptr() as *const c_void) }; - if error < 0 { - println!("error dropping wasi_pipe_t: {error}"); - } - } -} - impl fmt::Debug for wasi_pipe_t { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "wasi_pipe_t") @@ -121,7 +107,7 @@ impl io::Read for wasi_pipe_t { let mut data = self.get_data_mut("read")?; let result = unsafe { let ptr = buf.as_mut_ptr() as *mut c_char; - (self_read)(data.as_mut_ptr() as *const c_void, ptr, buf.len()) + (self_read)(data.data.as_mut_ptr() as *const c_void, ptr, buf.len()) }; if result >= 0 { Ok(result as usize) @@ -140,7 +126,7 @@ impl io::Write for wasi_pipe_t { let mut data = self.get_data_mut("write")?; let result = unsafe { (self_write)( - data.as_mut_ptr() as *const c_void, + data.data.as_mut_ptr() as *const c_void, buf.as_ptr() as *const c_char, buf.len(), false, @@ -164,7 +150,7 @@ impl io::Write for wasi_pipe_t { let bytes_to_write = &[]; let result: i64 = unsafe { (self_write)( - data.as_mut_ptr() as *const c_void, + data.data.as_mut_ptr() as *const c_void, bytes_to_write.as_ptr(), 0, true, @@ -190,7 +176,7 @@ impl io::Seek for wasi_pipe_t { SeekFrom::End(s) => (1, s), SeekFrom::Current(s) => (2, s), }; - let result = unsafe { (self_seek)(data.as_mut_ptr() as *const c_void, id, pos) }; + let result = unsafe { (self_seek)(data.data.as_mut_ptr() as *const c_void, id, pos) }; if result >= 0 { Ok(result.try_into().unwrap_or(0)) } else { @@ -213,9 +199,7 @@ impl VirtualFile for wasi_pipe_t { 0 } fn size(&self) -> u64 { - self.get_data_mut("size") - .map(|s| s.len() as u64) - .unwrap_or(0) + 0 } fn set_len(&mut self, _: u64) -> Result<(), FsError> { Ok(()) @@ -241,8 +225,10 @@ pub unsafe extern "C" fn wasi_pipe_new_internal( read, write, seek, - destructor, - data: Some(Box::new(Arc::new(Mutex::new(data_vec)))), + data: Some(Box::new(Arc::new(Mutex::new(WasiPipeDataWithDestructor { + data: data_vec, + destructor, + })))), })) } From aa4b1d06841d7522a6fe0572824aa02849a7e02f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 11:03:07 +0200 Subject: [PATCH 41/65] Add bytes_available function --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index a6fee8d28a8..fae461d4321 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -207,6 +207,16 @@ impl VirtualFile for wasi_pipe_t { fn unlink(&mut self) -> Result<(), FsError> { Ok(()) } + fn bytes_available(&self) -> Result { + Ok(self.bytes_available_read()?.unwrap_or(0usize) + + self.bytes_available_write()?.unwrap_or(0usize)) + } + fn bytes_available_read(&self) -> Result, FsError> { + Ok(None) + } + fn bytes_available_write(&self) -> Result, FsError> { + Ok(None) + } } #[no_mangle] From 1825e60b28cccda6b3269027b1a115891889baa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 11:06:59 +0200 Subject: [PATCH 42/65] Rename inherit_stdout -> stdout --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index fae461d4321..6dd6aae6df2 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -514,9 +514,9 @@ pub unsafe extern "C" fn wasi_pipe_seek( #[derive(Debug)] #[allow(non_camel_case_types)] pub struct wasi_config_t { - inherit_stdout: Option>, - inherit_stderr: Option>, - inherit_stdin: Option>, + stdout: Option>, + stderr: Option>, + stdin: Option>, state_builder: WasiStateBuilder, } @@ -530,9 +530,9 @@ pub unsafe extern "C" fn wasi_config_new( let prog_name = c_try!(name_c_str.to_str()); Some(Box::new(wasi_config_t { - inherit_stdout: None, - inherit_stderr: None, - inherit_stdin: None, + stdout: None, + stderr: None, + stdin: None, state_builder: WasiState::new(prog_name), })) } @@ -623,32 +623,32 @@ pub unsafe extern "C" fn wasi_config_mapdir( #[no_mangle] pub extern "C" fn wasi_config_capture_stdout(config: &mut wasi_config_t) { - config.inherit_stdout = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); + config.stdout = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { - config.inherit_stdout = None; + config.stdout = None; } #[no_mangle] pub extern "C" fn wasi_config_capture_stderr(config: &mut wasi_config_t) { - config.inherit_stderr = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); + config.stderr = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { - config.inherit_stderr = None; + config.stderr = None; } #[no_mangle] pub extern "C" fn wasi_config_capture_stdin(config: &mut wasi_config_t) { - config.inherit_stdin = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); + config.stdin = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { - config.inherit_stdin = None; + config.stdin = None; } #[no_mangle] @@ -693,15 +693,15 @@ pub unsafe extern "C" fn wasi_env_new( let store = &mut store?.inner; let mut store_mut = store.store_mut(); - if let Some(stdout) = config.inherit_stdout { + if let Some(stdout) = config.stdout { config.state_builder.stdout(stdout); } - if let Some(stderr) = config.inherit_stderr { + if let Some(stderr) = config.stderr { config.state_builder.stderr(stderr); } - if let Some(stdin) = config.inherit_stdin { + if let Some(stdin) = config.stdin { config.state_builder.stdin(stdin); } From 0e53d2d19b845d2475518489c0c7577fa7b302de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 11:17:29 +0200 Subject: [PATCH 43/65] Rename WasiPipePair -> WasiBidirectionalPipePair --- examples/wasi_pipes.rs | 6 ++--- lib/c-api/src/wasm_c_api/wasi/mod.rs | 4 ++-- lib/wasi/src/lib.rs | 2 +- lib/wasi/src/state/pipe.rs | 36 ++++++++++++++-------------- lib/wasi/src/syscalls/mod.rs | 4 ++-- lib/wasi/tests/stdio.rs | 8 +++---- tests/lib/wast/src/wasi_wast.rs | 4 ++-- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index af78daae4e0..2f7c318ce7a 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -14,7 +14,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; -use wasmer_wasi::{WasiPipePair, WasiState}; +use wasmer_wasi::{WasiBidirectionalPipePair, WasiState}; fn main() -> Result<(), Box> { let wasm_path = concat!( @@ -36,8 +36,8 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` with the stdio pipes - let mut input = WasiPipePair::new_arc(); - let mut output = WasiPipePair::new_arc(); + let mut input = WasiBidirectionalPipePair::new_arc(); + let mut output = WasiBidirectionalPipePair::new_arc(); let wasi_env = WasiState::new("hello") .stdin(Box::new(input.clone())) .stdout(Box::new(output.clone())) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 6dd6aae6df2..3ee77bdb25b 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -23,7 +23,7 @@ use std::{ sync::MutexGuard, }; use wasmer_wasi::{ - get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiPipePair, + get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiBidirectionalPipePair, WasiState, WasiStateBuilder, WasiVersion, }; @@ -352,7 +352,7 @@ unsafe extern "C" fn wasi_pipe_delete_memory_2(ptr: *const c_void /* = *WasiPipe pub unsafe extern "C" fn wasi_pipe_new(ptr_user: &mut *mut wasi_pipe_t) -> *mut wasi_pipe_t { use std::mem::ManuallyDrop; - let pair = WasiPipePair::new(); + let pair = WasiBidirectionalPipePair::new(); let mut data1 = ManuallyDrop::new(pair.send); let ptr1: &mut WasiPipe = &mut data1; diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 65664efd00f..13c8b52a3b0 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -43,7 +43,7 @@ mod utils; use crate::syscalls::*; pub use crate::state::{ - Fd, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiPipe, WasiPipePair, WasiState, + Fd, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiPipe, WasiBidirectionalPipePair, WasiState, WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, }; pub use crate::syscalls::types; diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 4672409af41..17aaa5eff23 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -23,12 +23,12 @@ pub struct WasiPipe { /// Pipe pair of (a, b) WasiPipes that are connected together #[derive(Debug)] -pub struct WasiPipePair { +pub struct WasiBidirectionalPipePair { pub send: WasiPipe, pub recv: WasiPipe, } -impl Write for WasiPipePair { +impl Write for WasiBidirectionalPipePair { fn write(&mut self, buf: &[u8]) -> io::Result { self.send.write(buf) } @@ -37,19 +37,19 @@ impl Write for WasiPipePair { } } -impl Seek for WasiPipePair { +impl Seek for WasiBidirectionalPipePair { fn seek(&mut self, _: SeekFrom) -> io::Result { Ok(0) } } -impl Read for WasiPipePair { +impl Read for WasiBidirectionalPipePair { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.recv.read(buf) } } -impl VirtualFile for WasiPipePair { +impl VirtualFile for WasiBidirectionalPipePair { fn last_accessed(&self) -> u64 { self.recv.last_accessed() } @@ -73,14 +73,14 @@ impl VirtualFile for WasiPipePair { } } -impl Default for WasiPipePair { +impl Default for WasiBidirectionalPipePair { fn default() -> Self { Self::new() } } -impl WasiPipePair { - pub fn new() -> WasiPipePair { +impl WasiBidirectionalPipePair { + pub fn new() -> WasiBidirectionalPipePair { let (tx1, rx1) = mpsc::channel(); let (tx2, rx2) = mpsc::channel(); @@ -96,27 +96,27 @@ impl WasiPipePair { read_buffer: None, }; - WasiPipePair { + WasiBidirectionalPipePair { send: pipe1, recv: pipe2, } } - pub fn new_arc() -> WasiSharedPipePair { - WasiSharedPipePair { + pub fn new_arc() -> WasiBidirectionalSharedPipePair { + WasiBidirectionalSharedPipePair { inner: Arc::new(Mutex::new(Self::new())), } } } -/// Shared version of WasiPipePair for situations where you need +/// Shared version of WasiBidirectionalPipePair for situations where you need /// to emulate the old behaviour of `Pipe` (both send and recv on one channel). #[derive(Debug, Clone)] -pub struct WasiSharedPipePair { - inner: Arc>, +pub struct WasiBidirectionalSharedPipePair { + inner: Arc>, } -impl Write for WasiSharedPipePair { +impl Write for WasiBidirectionalSharedPipePair { fn write(&mut self, buf: &[u8]) -> io::Result { match self.inner.lock().as_mut().map(|l| l.write(buf)) { Ok(r) => r, @@ -131,13 +131,13 @@ impl Write for WasiSharedPipePair { } } -impl Seek for WasiSharedPipePair { +impl Seek for WasiBidirectionalSharedPipePair { fn seek(&mut self, _: SeekFrom) -> io::Result { Ok(0) } } -impl Read for WasiSharedPipePair { +impl Read for WasiBidirectionalSharedPipePair { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { match self.inner.lock().as_mut().map(|l| l.read(buf)) { Ok(r) => r, @@ -146,7 +146,7 @@ impl Read for WasiSharedPipePair { } } -impl VirtualFile for WasiSharedPipePair { +impl VirtualFile for WasiBidirectionalSharedPipePair { fn last_accessed(&self) -> u64 { self.inner.lock().map(|l| l.last_accessed()).unwrap_or(0) } diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 5725714f59b..7a6845e3cc4 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -32,7 +32,7 @@ use crate::{ state::{ self, fs_error_into_wasi_err, iterate_poll_events, net_error_into_wasi_err, poll, virtual_file_type_to_wasi_file_type, Fd, Inode, InodeSocket, InodeSocketKind, InodeVal, - Kind, PollEvent, PollEventBuilder, WasiPipePair, WasiState, MAX_SYMLINKS, + Kind, PollEvent, PollEventBuilder, WasiBidirectionalPipePair, WasiState, MAX_SYMLINKS, }, WasiEnv, WasiError, WasiThread, WasiThreadId, }; @@ -1807,7 +1807,7 @@ pub fn fd_pipe( let env = ctx.data(); let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(&ctx, 0); - let pipes = WasiPipePair::new(); + let pipes = WasiBidirectionalPipePair::new(); let pipe1 = pipes.send; let pipe2 = pipes.recv; diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 07ae9dc0206..0d953434338 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -1,7 +1,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; -use wasmer_wasi::{WasiPipe, WasiPipePair, WasiState}; +use wasmer_wasi::{WasiPipe, WasiBidirectionalPipePair, WasiState}; mod sys { #[test] @@ -73,7 +73,7 @@ fn test_stdout() { "#).unwrap(); // Create the `WasiEnv`. - let WasiPipePair { send, mut recv } = WasiPipePair::new(); + let WasiBidirectionalPipePair { send, mut recv } = WasiBidirectionalPipePair::new(); let wasi_env = WasiState::new("command-name") .args(&["Gordon"]) .stdout(Box::new(send)) @@ -110,7 +110,7 @@ fn test_env() { }); // Create the `WasiEnv`. - let WasiPipePair { send, mut recv } = WasiPipePair::new(); + let WasiBidirectionalPipePair { send, mut recv } = WasiBidirectionalPipePair::new(); let mut wasi_state_builder = WasiState::new("command-name"); wasi_state_builder .args(&["Gordon"]) @@ -146,7 +146,7 @@ fn test_stdin() { let module = Module::new(&store, include_bytes!("stdin-hello.wasm")).unwrap(); // Create the `WasiEnv`. - let mut pipe = WasiPipePair::new_arc(); + let mut pipe = WasiBidirectionalPipePair::new_arc(); // Write to STDIN let buf = "Hello, stdin!\n".as_bytes().to_owned(); diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 79a26d50219..accd540dfc2 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -9,7 +9,7 @@ use wasmer_vfs::{host_fs, mem_fs, FileSystem}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; use wasmer_wasi::{ generate_import_object_from_env, get_wasi_version, FsError, VirtualFile, WasiEnv, - WasiFunctionEnv, WasiPipePair, WasiState, WasiVersion, + WasiFunctionEnv, WasiBidirectionalPipePair, WasiState, WasiVersion, }; use wast::parser::{self, Parse, ParseBuffer, Parser}; @@ -143,7 +143,7 @@ impl<'a> WasiTest<'a> { )> { let mut builder = WasiState::new(self.wasm_path); - let stdin_pipe = WasiPipePair::new(); + let stdin_pipe = WasiBidirectionalPipePair::new(); builder.stdin(Box::new(stdin_pipe)); for (name, value) in &self.envs { From 238aef331b61b06a860dfacc13051fde7725c799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 11:22:17 +0200 Subject: [PATCH 44/65] Remove debug eprintln --- lib/wasi/src/state/pipe.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 17aaa5eff23..080f92d8ab5 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -297,7 +297,6 @@ impl Read for WasiPipe { // In this case, just return 0 to indicate that we can't read any // bytes anymore Err(e) => { - eprintln!("WasiPipe read error: {e}"); return Ok(0); } } From 64399973e33ea3edf8735965c9aa8820a8520dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 11:39:00 +0200 Subject: [PATCH 45/65] Reexport WasiBidirectionalSharedPipePair as Pipe --- examples/wasi_pipes.rs | 6 +++--- lib/wasi/src/state/pipe.rs | 22 +++++++++++++++------- lib/wasi/src/state/types.rs | 3 +++ lib/wasi/tests/stdio.rs | 4 ++-- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index 2f7c318ce7a..d88797ab2e4 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -14,7 +14,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; -use wasmer_wasi::{WasiBidirectionalPipePair, WasiState}; +use wasmer_wasi::{WasiBidirectionalSharedPipePair, WasiState}; fn main() -> Result<(), Box> { let wasm_path = concat!( @@ -36,8 +36,8 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` with the stdio pipes - let mut input = WasiBidirectionalPipePair::new_arc(); - let mut output = WasiBidirectionalPipePair::new_arc(); + let mut input = WasiBidirectionalSharedPipePair::new(); + let mut output = WasiBidirectionalSharedPipePair::new(); let wasi_env = WasiState::new("hello") .stdin(Box::new(input.clone())) .stdout(Box::new(output.clone())) diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 080f92d8ab5..ad9a3f76d52 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -101,12 +101,6 @@ impl WasiBidirectionalPipePair { recv: pipe2, } } - - pub fn new_arc() -> WasiBidirectionalSharedPipePair { - WasiBidirectionalSharedPipePair { - inner: Arc::new(Mutex::new(Self::new())), - } - } } /// Shared version of WasiBidirectionalPipePair for situations where you need @@ -116,6 +110,20 @@ pub struct WasiBidirectionalSharedPipePair { inner: Arc>, } +impl Default for WasiBidirectionalSharedPipePair { + fn default() -> Self { + Self::new() + } +} + +impl WasiBidirectionalSharedPipePair { + pub fn new() -> Self { + Self { + inner: Arc::new(Mutex::new(WasiBidirectionalPipePair::new())), + } + } +} + impl Write for WasiBidirectionalSharedPipePair { fn write(&mut self, buf: &[u8]) -> io::Result { match self.inner.lock().as_mut().map(|l| l.write(buf)) { @@ -296,7 +304,7 @@ impl Read for WasiPipe { // Errors can happen if the sender has been dropped already // In this case, just return 0 to indicate that we can't read any // bytes anymore - Err(e) => { + Err(_) => { return Ok(0); } } diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 7cc78c4a411..f5c30e102d4 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -370,6 +370,9 @@ pub(crate) fn poll( pub trait WasiPath {} +#[deprecated(since = "3.0.0-beta.2", note = "Moved to `wasmer_wasi::pipe::WasiBidirectionalSharedPipePair`, `Pipe` is only a transitional reexport")] +pub use crate::state::WasiBidirectionalSharedPipePair as Pipe; + /* TODO: Think about using this trait WasiFdBacking: std::fmt::Debug { diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 0d953434338..45178434424 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -1,7 +1,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; -use wasmer_wasi::{WasiPipe, WasiBidirectionalPipePair, WasiState}; +use wasmer_wasi::{WasiPipe, WasiBidirectionalSharedPipePair, WasiState}; mod sys { #[test] @@ -146,7 +146,7 @@ fn test_stdin() { let module = Module::new(&store, include_bytes!("stdin-hello.wasm")).unwrap(); // Create the `WasiEnv`. - let mut pipe = WasiBidirectionalPipePair::new_arc(); + let mut pipe = WasiBidirectionalSharedPipePair::new(); // Write to STDIN let buf = "Hello, stdin!\n".as_bytes().to_owned(); From f21689d1e6e49d90d30573a353a282c432fdee55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 12:27:33 +0200 Subject: [PATCH 46/65] Added set_blocking method to control blocking behaviour for WasiPipe --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 14 +++++++++- lib/wasi/src/state/pipe.rs | 39 +++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 3ee77bdb25b..1b0776c2302 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -350,9 +350,21 @@ unsafe extern "C" fn wasi_pipe_delete_memory_2(ptr: *const c_void /* = *WasiPipe /// for backing stdin / stdout / stderr #[no_mangle] pub unsafe extern "C" fn wasi_pipe_new(ptr_user: &mut *mut wasi_pipe_t) -> *mut wasi_pipe_t { + wasi_pipe_new_internal_memory(ptr_user, false) +} + +/// Same as `wasi_pipe_new`, but the pipe will block to wait for stdin input +#[no_mangle] +pub unsafe extern "C" fn wasi_pipe_new_blocking(ptr_user: &mut *mut wasi_pipe_t) -> *mut wasi_pipe_t { + wasi_pipe_new_internal_memory(ptr_user, true) +} + +unsafe fn wasi_pipe_new_internal_memory(ptr_user: &mut *mut wasi_pipe_t, blocking: bool) -> *mut wasi_pipe_t { use std::mem::ManuallyDrop; - let pair = WasiBidirectionalPipePair::new(); + let mut pair = WasiBidirectionalPipePair::new(); + pair.send.set_blocking(blocking); + pair.recv.set_blocking(blocking); let mut data1 = ManuallyDrop::new(pair.send); let ptr1: &mut WasiPipe = &mut data1; diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index ad9a3f76d52..94254fe02f9 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -19,6 +19,8 @@ pub struct WasiPipe { rx: Mutex>>, /// Buffers the last read message from the pipe while its being consumed read_buffer: Option, + /// Whether the pipe should block or not block to wait for stdin reads + block: bool, } /// Pipe pair of (a, b) WasiPipes that are connected together @@ -88,12 +90,14 @@ impl WasiBidirectionalPipePair { tx: Mutex::new(tx1), rx: Mutex::new(rx2), read_buffer: None, + block: true, }; let pipe2 = WasiPipe { tx: Mutex::new(tx2), rx: Mutex::new(rx1), read_buffer: None, + block: true, }; WasiBidirectionalPipePair { @@ -101,6 +105,17 @@ impl WasiBidirectionalPipePair { recv: pipe2, } } + + pub fn with_blocking(mut self, block: bool) -> Self { + self.set_blocking(block); + self + } + + /// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true` + pub fn set_blocking(&mut self, block: bool) { + self.send.set_blocking(block); + self.recv.set_blocking(block); + } } /// Shared version of WasiBidirectionalPipePair for situations where you need @@ -122,6 +137,16 @@ impl WasiBidirectionalSharedPipePair { inner: Arc::new(Mutex::new(WasiBidirectionalPipePair::new())), } } + + pub fn with_blocking(mut self, block: bool) -> Self { + self.set_blocking(block); + self + } + + /// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true` + pub fn set_blocking(&mut self, block: bool) { + self.inner.lock().unwrap().set_blocking(block); + } } impl Write for WasiBidirectionalSharedPipePair { @@ -188,6 +213,18 @@ impl VirtualFile for WasiBidirectionalSharedPipePair { } impl WasiPipe { + + /// Same as `set_blocking`, but as a builder method + pub fn with_blocking(mut self, block: bool) -> Self { + self.set_blocking(block); + self + } + + /// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true` + pub fn set_blocking(&mut self, block: bool) { + self.block = block; + } + pub fn recv( &mut self, memory: &MemoryView, @@ -278,7 +315,7 @@ impl Read for WasiPipe { inner_buf.advance(read); return Ok(read); } - } else { + } else if !self.block { return Ok(0); } } From 72acbc8f93f4ce0bc9e7bf70d8c5357cea6c5198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 12:28:27 +0200 Subject: [PATCH 47/65] cargo fmt --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 13 +++++++++---- lib/wasi/src/lib.rs | 2 +- lib/wasi/src/state/pipe.rs | 3 +-- lib/wasi/src/state/types.rs | 5 ++++- lib/wasi/tests/stdio.rs | 2 +- tests/lib/wast/src/wasi_wast.rs | 4 ++-- 6 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 1b0776c2302..b6426722156 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -23,8 +23,8 @@ use std::{ sync::MutexGuard, }; use wasmer_wasi::{ - get_wasi_version, FsError, VirtualFile, WasiFile, WasiFunctionEnv, WasiPipe, WasiBidirectionalPipePair, - WasiState, WasiStateBuilder, WasiVersion, + get_wasi_version, FsError, VirtualFile, WasiBidirectionalPipePair, WasiFile, WasiFunctionEnv, + WasiPipe, WasiState, WasiStateBuilder, WasiVersion, }; /// Function callback that takes: @@ -355,11 +355,16 @@ pub unsafe extern "C" fn wasi_pipe_new(ptr_user: &mut *mut wasi_pipe_t) -> *mut /// Same as `wasi_pipe_new`, but the pipe will block to wait for stdin input #[no_mangle] -pub unsafe extern "C" fn wasi_pipe_new_blocking(ptr_user: &mut *mut wasi_pipe_t) -> *mut wasi_pipe_t { +pub unsafe extern "C" fn wasi_pipe_new_blocking( + ptr_user: &mut *mut wasi_pipe_t, +) -> *mut wasi_pipe_t { wasi_pipe_new_internal_memory(ptr_user, true) } -unsafe fn wasi_pipe_new_internal_memory(ptr_user: &mut *mut wasi_pipe_t, blocking: bool) -> *mut wasi_pipe_t { +unsafe fn wasi_pipe_new_internal_memory( + ptr_user: &mut *mut wasi_pipe_t, + blocking: bool, +) -> *mut wasi_pipe_t { use std::mem::ManuallyDrop; let mut pair = WasiBidirectionalPipePair::new(); diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 13c8b52a3b0..e85ac1d0ecc 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -43,7 +43,7 @@ mod utils; use crate::syscalls::*; pub use crate::state::{ - Fd, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiPipe, WasiBidirectionalPipePair, WasiState, + Fd, Stderr, Stdin, Stdout, WasiBidirectionalPipePair, WasiFs, WasiInodes, WasiPipe, WasiState, WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, }; pub use crate::syscalls::types; diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 94254fe02f9..f182ae179fc 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -213,13 +213,12 @@ impl VirtualFile for WasiBidirectionalSharedPipePair { } impl WasiPipe { - /// Same as `set_blocking`, but as a builder method pub fn with_blocking(mut self, block: bool) -> Self { self.set_blocking(block); self } - + /// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true` pub fn set_blocking(&mut self, block: bool) { self.block = block; diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index f5c30e102d4..5c921ddc5a5 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -370,7 +370,10 @@ pub(crate) fn poll( pub trait WasiPath {} -#[deprecated(since = "3.0.0-beta.2", note = "Moved to `wasmer_wasi::pipe::WasiBidirectionalSharedPipePair`, `Pipe` is only a transitional reexport")] +#[deprecated( + since = "3.0.0-beta.2", + note = "Moved to `wasmer_wasi::pipe::WasiBidirectionalSharedPipePair`, `Pipe` is only a transitional reexport" +)] pub use crate::state::WasiBidirectionalSharedPipePair as Pipe; /* diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 45178434424..4aebb3a567a 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -1,7 +1,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; -use wasmer_wasi::{WasiPipe, WasiBidirectionalSharedPipePair, WasiState}; +use wasmer_wasi::{WasiBidirectionalSharedPipePair, WasiPipe, WasiState}; mod sys { #[test] diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index accd540dfc2..5f3ac901723 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -8,8 +8,8 @@ use wasmer::{Imports, Instance, Module, Store}; use wasmer_vfs::{host_fs, mem_fs, FileSystem}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; use wasmer_wasi::{ - generate_import_object_from_env, get_wasi_version, FsError, VirtualFile, WasiEnv, - WasiFunctionEnv, WasiBidirectionalPipePair, WasiState, WasiVersion, + generate_import_object_from_env, get_wasi_version, FsError, VirtualFile, + WasiBidirectionalPipePair, WasiEnv, WasiFunctionEnv, WasiState, WasiVersion, }; use wast::parser::{self, Parse, ParseBuffer, Parser}; From 497592a04c1de4f30679b0c0050c4784e22d14bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 13:50:23 +0200 Subject: [PATCH 48/65] Allow dead code (?) --- lib/wasi/src/state/pipe.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index f182ae179fc..819bd009875 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -106,12 +106,14 @@ impl WasiBidirectionalPipePair { } } + #[allow(dead_code)] pub fn with_blocking(mut self, block: bool) -> Self { self.set_blocking(block); self } /// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true` + #[allow(dead_code)] pub fn set_blocking(&mut self, block: bool) { self.send.set_blocking(block); self.recv.set_blocking(block); @@ -138,12 +140,14 @@ impl WasiBidirectionalSharedPipePair { } } + #[allow(dead_code)] pub fn with_blocking(mut self, block: bool) -> Self { self.set_blocking(block); self } /// Whether to block on reads (ususally for waiting for stdin keyboard input). Default: `true` + #[allow(dead_code)] pub fn set_blocking(&mut self, block: bool) { self.inner.lock().unwrap().set_blocking(block); } From 8aa69d2b632438f6e3705a31c4dd1471d7e1d9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 14:17:10 +0200 Subject: [PATCH 49/65] Try fixing failing JS tests --- lib/wasi/src/lib.rs | 4 +++- lib/wasi/tests/stdio.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index e85ac1d0ecc..8777d92d7b1 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -43,7 +43,9 @@ mod utils; use crate::syscalls::*; pub use crate::state::{ - Fd, Stderr, Stdin, Stdout, WasiBidirectionalPipePair, WasiFs, WasiInodes, WasiPipe, WasiState, + Fd, Stderr, Stdin, Stdout, + WasiBidirectionalPipePair, WasiBidirectionalSharedPipePair, Pipe, + WasiFs, WasiInodes, WasiPipe, WasiState, WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, }; pub use crate::syscalls::types; diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 4aebb3a567a..8162cd1b6e5 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -1,7 +1,7 @@ use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; -use wasmer_wasi::{WasiBidirectionalSharedPipePair, WasiPipe, WasiState}; +use wasmer_wasi::{WasiBidirectionalSharedPipePair, WasiState}; mod sys { #[test] @@ -73,10 +73,10 @@ fn test_stdout() { "#).unwrap(); // Create the `WasiEnv`. - let WasiBidirectionalPipePair { send, mut recv } = WasiBidirectionalPipePair::new(); + let mut pipe = WasiBidirectionalSharedPipePair::new(); let wasi_env = WasiState::new("command-name") .args(&["Gordon"]) - .stdout(Box::new(send)) + .stdout(Box::new(pipe.clone())) .finalize(&mut store) .unwrap(); @@ -93,7 +93,7 @@ fn test_stdout() { start.call(&mut store, &[]).unwrap(); let mut stdout_str = String::new(); - recv.read_to_string(&mut stdout_str).unwrap(); + pipe.read_to_string(&mut stdout_str).unwrap(); let stdout_as_str = stdout_str.as_str(); assert_eq!(stdout_as_str, "hello world\n"); } @@ -110,7 +110,7 @@ fn test_env() { }); // Create the `WasiEnv`. - let WasiBidirectionalPipePair { send, mut recv } = WasiBidirectionalPipePair::new(); + let mut pipe = WasiBidirectionalSharedPipePair::new(); let mut wasi_state_builder = WasiState::new("command-name"); wasi_state_builder .args(&["Gordon"]) @@ -119,7 +119,7 @@ fn test_env() { .env("TEST2", "VALUE2"); // panic!("envs: {:?}", wasi_state_builder.envs); let wasi_env = wasi_state_builder - .stdout(Box::new(send)) + .stdout(Box::new(pipe.clone())) .finalize(&mut store) .unwrap(); @@ -136,7 +136,7 @@ fn test_env() { start.call(&mut store, &[]).unwrap(); let mut stdout_str = String::new(); - recv.read_to_string(&mut stdout_str).unwrap(); + pipe.read_to_string(&mut stdout_str).unwrap(); let stdout_as_str = stdout_str.as_str(); assert_eq!(stdout_as_str, "Env vars:\nDOG=X\nTEST2=VALUE2\nTEST=VALUE\nDOG Ok(\"X\")\nDOG_TYPE Err(NotPresent)\nSET VAR Ok(\"HELLO\")\n"); } From 0e5b55f8456a50e24256eeb53bd6c402fb1f8127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 14:19:16 +0200 Subject: [PATCH 50/65] Set blocking = false for all tests --- examples/wasi_pipes.rs | 4 ++-- lib/wasi/tests/stdio.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index d88797ab2e4..e4319b71688 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -36,8 +36,8 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` with the stdio pipes - let mut input = WasiBidirectionalSharedPipePair::new(); - let mut output = WasiBidirectionalSharedPipePair::new(); + let mut input = WasiBidirectionalSharedPipePair::new().with_blocking(false); + let mut output = WasiBidirectionalSharedPipePair::new().with_blocking(false); let wasi_env = WasiState::new("hello") .stdin(Box::new(input.clone())) .stdout(Box::new(output.clone())) diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 8162cd1b6e5..5c759d76c1a 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -73,7 +73,7 @@ fn test_stdout() { "#).unwrap(); // Create the `WasiEnv`. - let mut pipe = WasiBidirectionalSharedPipePair::new(); + let mut pipe = WasiBidirectionalSharedPipePair::new().with_blocking(false); let wasi_env = WasiState::new("command-name") .args(&["Gordon"]) .stdout(Box::new(pipe.clone())) @@ -110,7 +110,7 @@ fn test_env() { }); // Create the `WasiEnv`. - let mut pipe = WasiBidirectionalSharedPipePair::new(); + let mut pipe = WasiBidirectionalSharedPipePair::new().with_blocking(false); let mut wasi_state_builder = WasiState::new("command-name"); wasi_state_builder .args(&["Gordon"]) @@ -146,7 +146,7 @@ fn test_stdin() { let module = Module::new(&store, include_bytes!("stdin-hello.wasm")).unwrap(); // Create the `WasiEnv`. - let mut pipe = WasiBidirectionalSharedPipePair::new(); + let mut pipe = WasiBidirectionalSharedPipePair::new().with_blocking(false); // Write to STDIN let buf = "Hello, stdin!\n".as_bytes().to_owned(); From 6a91ed77e504275c6a1a8643e24e5b74035e4bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 19 Sep 2022 14:20:08 +0200 Subject: [PATCH 51/65] cargo fmt --- lib/wasi/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 8777d92d7b1..e551329dd1a 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -43,10 +43,9 @@ mod utils; use crate::syscalls::*; pub use crate::state::{ - Fd, Stderr, Stdin, Stdout, - WasiBidirectionalPipePair, WasiBidirectionalSharedPipePair, Pipe, - WasiFs, WasiInodes, WasiPipe, WasiState, - WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, + Fd, Pipe, Stderr, Stdin, Stdout, WasiBidirectionalPipePair, WasiBidirectionalSharedPipePair, + WasiFs, WasiInodes, WasiPipe, WasiState, WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, + VIRTUAL_ROOT_FD, }; pub use crate::syscalls::types; #[cfg(feature = "wasix")] From 7d44c135f8eb7c31815438f8dfc86aa92c787b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Thu, 22 Sep 2022 19:20:06 +0200 Subject: [PATCH 52/65] Prevent CI from locking up when running WasiTest --- tests/lib/wast/src/wasi_wast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 5f3ac901723..996bee29a5f 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -143,7 +143,7 @@ impl<'a> WasiTest<'a> { )> { let mut builder = WasiState::new(self.wasm_path); - let stdin_pipe = WasiBidirectionalPipePair::new(); + let stdin_pipe = WasiBidirectionalPipePair::new().with_blocking(false); builder.stdin(Box::new(stdin_pipe)); for (name, value) in &self.envs { From 703dbce37d421f069d885676d3c14534333ef1d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Wed, 28 Sep 2022 14:34:59 +0200 Subject: [PATCH 53/65] Fix ambigouusly named "config" and "stdin" params --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index e85381d5be6..dba1c929111 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -670,26 +670,26 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdin( - config: &mut wasi_config_t, - stdin: *mut wasi_pipe_t, + config_overwrite: &mut wasi_config_t, + stdin_overwrite: *mut wasi_pipe_t, ) { - config.state_builder.stdin(Box::from_raw(stdin)); + config_overwrite.state_builder.stdin(Box::from_raw(stdin_overwrite)); } #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stdout( - config: &mut wasi_config_t, - stdout: *mut wasi_pipe_t, + config_overwrite: &mut wasi_config_t, + stdout_overwrite: *mut wasi_pipe_t, ) { - config.state_builder.stdout(Box::from_raw(stdout)); + config_overwrite.state_builder.stdout(Box::from_raw(stdout_overwrite)); } #[no_mangle] pub unsafe extern "C" fn wasi_config_overwrite_stderr( - config: &mut wasi_config_t, - stderr: *mut wasi_pipe_t, + config_overwrite: &mut wasi_config_t, + stderr_overwrite: *mut wasi_pipe_t, ) { - config.state_builder.stderr(Box::from_raw(stderr)); + config_overwrite.state_builder.stderr(Box::from_raw(stderr_overwrite)); } #[allow(non_camel_case_types)] From 28c0e9c63f8c76cec95e0f1e0e35cfd9f4dd9689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Wed, 28 Sep 2022 14:35:51 +0200 Subject: [PATCH 54/65] cargo fmt --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index dba1c929111..410fe0e809c 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -673,7 +673,9 @@ pub unsafe extern "C" fn wasi_config_overwrite_stdin( config_overwrite: &mut wasi_config_t, stdin_overwrite: *mut wasi_pipe_t, ) { - config_overwrite.state_builder.stdin(Box::from_raw(stdin_overwrite)); + config_overwrite + .state_builder + .stdin(Box::from_raw(stdin_overwrite)); } #[no_mangle] @@ -681,7 +683,9 @@ pub unsafe extern "C" fn wasi_config_overwrite_stdout( config_overwrite: &mut wasi_config_t, stdout_overwrite: *mut wasi_pipe_t, ) { - config_overwrite.state_builder.stdout(Box::from_raw(stdout_overwrite)); + config_overwrite + .state_builder + .stdout(Box::from_raw(stdout_overwrite)); } #[no_mangle] @@ -689,7 +693,9 @@ pub unsafe extern "C" fn wasi_config_overwrite_stderr( config_overwrite: &mut wasi_config_t, stderr_overwrite: *mut wasi_pipe_t, ) { - config_overwrite.state_builder.stderr(Box::from_raw(stderr_overwrite)); + config_overwrite + .state_builder + .stderr(Box::from_raw(stderr_overwrite)); } #[allow(non_camel_case_types)] From 68bc7cc14a708c5253cd88057b4ddd56105750af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 11 Oct 2022 12:05:26 +0200 Subject: [PATCH 55/65] Fix merge issues --- lib/wasi/src/syscalls/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 230a6c6083f..84572ad4bd4 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -42,7 +42,7 @@ use crate::{ mem_error_to_wasi, state::{ self, fs_error_into_wasi_err, iterate_poll_events, net_error_into_wasi_err, poll, - virtual_file_type_to_wasi_file_type, Fd, Inode, InodeSocket, InodeSocketKind, InodeVal, + virtual_file_type_to_wasi_file_type, Inode, InodeSocket, InodeSocketKind, InodeVal, Kind, PollEvent, PollEventBuilder, WasiBidirectionalPipePair, WasiState, MAX_SYMLINKS, }, Fd, WasiEnv, WasiError, WasiThread, WasiThreadId, From 3eb2008ed7a19915746192b856c1caf59cd39625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 11 Oct 2022 12:07:33 +0200 Subject: [PATCH 56/65] cargo fmt --- lib/wasi/src/syscalls/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 84572ad4bd4..e5c3e3ec2da 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -42,8 +42,8 @@ use crate::{ mem_error_to_wasi, state::{ self, fs_error_into_wasi_err, iterate_poll_events, net_error_into_wasi_err, poll, - virtual_file_type_to_wasi_file_type, Inode, InodeSocket, InodeSocketKind, InodeVal, - Kind, PollEvent, PollEventBuilder, WasiBidirectionalPipePair, WasiState, MAX_SYMLINKS, + virtual_file_type_to_wasi_file_type, Inode, InodeSocket, InodeSocketKind, InodeVal, Kind, + PollEvent, PollEventBuilder, WasiBidirectionalPipePair, WasiState, MAX_SYMLINKS, }, Fd, WasiEnv, WasiError, WasiThread, WasiThreadId, }; From b20b88b04f4f91ec2eeb9a1ebb62ff306fbdb098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 11 Oct 2022 16:21:08 +0200 Subject: [PATCH 57/65] WIP: prepare buffered reads to Pipe instead of reading data on-demand --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 87 +++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 410fe0e809c..d000d61c725 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -60,9 +60,47 @@ pub struct wasi_pipe_t { struct WasiPipeDataWithDestructor { data: Vec, + // Buffer of already-read data that is being read into, + // then the result is returned + temp_buffer: Vec, destructor: WasiConsoleIoEnvDestructor, } +impl WasiPipeDataWithDestructor { + fn read_buffer(&mut self, read_cb: WasiConsoleIoReadCallback, max_read: Option) -> io::Result> { + + const BLOCK_SIZE: usize = 1024; + + let mut final_buf = Vec::new(); + + match max_read { + None => { + // read from pipe until EOF encountered + }, + Some(max) => { + // read from pipe until either EOF or maximum number of bytes + for i in + } + } + + /* + let result = unsafe { + let ptr = buf.as_mut_ptr() as *mut c_char; + (self_read)(data.data.as_mut_ptr() as *const c_void, ptr, buf.len()) + }; + if result >= 0 { + Ok(result as usize) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + format!("could not read from wasi_pipe_t: {result}"), + )) + } + */ + + } +} + impl Drop for WasiPipeDataWithDestructor { fn drop(&mut self) { let error = unsafe { (self.destructor)(self.data.as_mut_ptr() as *const c_void) }; @@ -73,6 +111,15 @@ impl Drop for WasiPipeDataWithDestructor { } impl wasi_pipe_t { + + /// Read bytes from this pipe into the internal buffer, + /// returning how many bytes were read + fn read_from_pipe_store_in_buffer(&self) -> io::Result { + let mut data = self.get_data_mut("read_from_pipe")?; + data.read_into_buffer(); + Ok(data.temp_buffer.len()) + } + fn get_data_mut( &self, op_id: &'static str, @@ -105,17 +152,8 @@ impl io::Read for wasi_pipe_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { let self_read = self.read; let mut data = self.get_data_mut("read")?; - let result = unsafe { - let ptr = buf.as_mut_ptr() as *mut c_char; - (self_read)(data.data.as_mut_ptr() as *const c_void, ptr, buf.len()) - }; - if result >= 0 { - Ok(result as usize) - } else { - Err(io::Error::new( - io::ErrorKind::Other, - format!("could not read from wasi_pipe_t: {result}"), - )) + if data.temp_buffer.len() >= buf.len() { + // fill up buf by draining temp_buffer first, then read more bytes } } } @@ -212,7 +250,7 @@ impl VirtualFile for wasi_pipe_t { + self.bytes_available_write()?.unwrap_or(0usize)) } fn bytes_available_read(&self) -> Result, FsError> { - Ok(None) + let read = self.read_from_pipe_store_in_buffer(); } fn bytes_available_write(&self) -> Result, FsError> { Ok(None) @@ -237,6 +275,7 @@ pub unsafe extern "C" fn wasi_pipe_new_internal( seek, data: Some(Box::new(Arc::new(Mutex::new(WasiPipeDataWithDestructor { data: data_vec, + temp_buffer: Vec::new(), destructor, })))), })) @@ -461,15 +500,17 @@ pub unsafe extern "C" fn wasi_pipe_delete_str(buf: *mut c_char) { let _ = CString::from_raw(buf); } -#[no_mangle] -pub unsafe extern "C" fn wasi_pipe_read_str(ptr: *const wasi_pipe_t, buf: *mut *mut c_char) -> i64 { - use std::ffi::CString; +unsafe fn wasi_pipe_read_bytes_internal( + ptr: *const wasi_pipe_t, + buf: &mut Vec +) -> i64 { + use std::io::Read; const BLOCK_SIZE: usize = 1024; - let mut target = Vec::new(); let ptr = &mut *(ptr as *mut wasi_pipe_t); + let mut target = Vec::new(); loop { let mut v = vec![0; BLOCK_SIZE]; @@ -487,6 +528,20 @@ pub unsafe extern "C" fn wasi_pipe_read_str(ptr: *const wasi_pipe_t, buf: *mut * } } + *buf = target; + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn wasi_pipe_read_str(ptr: *const wasi_pipe_t, buf: *mut *mut c_char) -> i64 { + use std::ffi::CString; + + let mut target = Vec::new(); + let read_result = wasi_pipe_read_bytes_internal(ptr, &mut target); + if read_result < 0 { + return read_result; + } + target.push(0); let len = target.len(); let c_string = match CString::from_vec_with_nul(target.clone()) { From 6b5c746a069579da9c66b59c7097192fedbf8378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Wed, 12 Oct 2022 07:42:35 +0200 Subject: [PATCH 58/65] Fix PR review comments from john --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 75 +++++++++++++++++++--------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index d000d61c725..916454ef12b 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -73,31 +73,42 @@ impl WasiPipeDataWithDestructor { let mut final_buf = Vec::new(); - match max_read { - None => { - // read from pipe until EOF encountered - }, - Some(max) => { - // read from pipe until either EOF or maximum number of bytes - for i in + let max_read = max_read.unwrap_or(usize::MAX); + let mut cur_read = 0; + + // Read bytes until either EOF is reached or max_read bytes are reached + loop { + if cur_read >= max_read { + break; } - } - /* - let result = unsafe { - let ptr = buf.as_mut_ptr() as *mut c_char; - (self_read)(data.data.as_mut_ptr() as *const c_void, ptr, buf.len()) - }; - if result >= 0 { - Ok(result as usize) - } else { - Err(io::Error::new( - io::ErrorKind::Other, - format!("could not read from wasi_pipe_t: {result}"), - )) + let mut temp_buffer = if cur_read + BLOCK_SIZE > max_read { + vec![0;max_read - cur_read] + } else { + vec![0;BLOCK_SIZE] + }; + + let result = unsafe { + let ptr = temp_buffer.as_mut_ptr() as *mut c_char; + (read_cb)(self.data.as_mut_ptr() as *const c_void, ptr, temp_buffer.len()) + }; + + if result < 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("could not read from wasi_pipe_t: {result}"), + )); + } + + if result == 0 { + break; // EOF + } + + cur_read += temp_buffer.len(); + final_buf.append(&mut temp_buffer); } - */ + Ok(final_buf) } } @@ -150,11 +161,24 @@ impl fmt::Debug for wasi_pipe_t { impl io::Read for wasi_pipe_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { + let self_read = self.read; let mut data = self.get_data_mut("read")?; - if data.temp_buffer.len() >= buf.len() { - // fill up buf by draining temp_buffer first, then read more bytes + + // fill up buf by draining temp_buffer first, then read more bytes + let bytes_to_read = data.temp_buffer.len().min(buf.len()); + let temp_buffer_drained: Vec<_> = data.temp_buffer.drain(..bytes_to_read).collect(); + assert!(temp_buffer_drained.len() <= buf.len()); + + // If temp_buffer is exhausted, try reading the remaining bytes from the pipe + if buf.len() >= temp_buffer_drained.len() { + let secondary_bytes_to_read = data.temp_buffer.len().min(buf.len()); + data.read_buffer(self_read, Some(secondary_bytes_to_read))?; + temp_buffer_drained.append(data.temp_buffer.drain(..secondary_bytes_to_read).collect()); } + + assert_eq!(buf.len(), temp_buffer_drained.len()); + buf.clone_from_slice(&temp_buffer_drained); } } @@ -250,7 +274,10 @@ impl VirtualFile for wasi_pipe_t { + self.bytes_available_write()?.unwrap_or(0usize)) } fn bytes_available_read(&self) -> Result, FsError> { - let read = self.read_from_pipe_store_in_buffer(); + let self_read = self.read; + let mut data = self.get_data_mut("bytes_available_read")?; + data.read_buffer(self_read, None)?; + Ok(Some(data.temp_buffer.len())) } fn bytes_available_write(&self) -> Result, FsError> { Ok(None) From 24228881dc03c5e2b7c315e2df1ad9da7844f8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 12:55:09 +0200 Subject: [PATCH 59/65] Fix CI issues --- Cargo.lock | 4 ++-- lib/c-api/src/wasm_c_api/wasi/mod.rs | 16 ++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a4aa7427890..c2f5c1e2b26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3334,9 +3334,9 @@ dependencies = [ [[package]] name = "wasmer-inline-c" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2405c99de49dc05338e5ed2eb397fe70b7128340d960507d0ba716f7d29a91a" +checksum = "7c4e7a2a3363ceeb2ee60371af9460748f2bf53569b58627f1f640284ab07778" dependencies = [ "assert_cmd", "cc", diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 916454ef12b..1f5eac3af02 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -123,14 +123,6 @@ impl Drop for WasiPipeDataWithDestructor { impl wasi_pipe_t { - /// Read bytes from this pipe into the internal buffer, - /// returning how many bytes were read - fn read_from_pipe_store_in_buffer(&self) -> io::Result { - let mut data = self.get_data_mut("read_from_pipe")?; - data.read_into_buffer(); - Ok(data.temp_buffer.len()) - } - fn get_data_mut( &self, op_id: &'static str, @@ -167,18 +159,22 @@ impl io::Read for wasi_pipe_t { // fill up buf by draining temp_buffer first, then read more bytes let bytes_to_read = data.temp_buffer.len().min(buf.len()); - let temp_buffer_drained: Vec<_> = data.temp_buffer.drain(..bytes_to_read).collect(); + let mut temp_buffer_drained: Vec<_> = data.temp_buffer.drain(..bytes_to_read).collect(); assert!(temp_buffer_drained.len() <= buf.len()); // If temp_buffer is exhausted, try reading the remaining bytes from the pipe + let mut bytes_read = bytes_to_read; if buf.len() >= temp_buffer_drained.len() { let secondary_bytes_to_read = data.temp_buffer.len().min(buf.len()); data.read_buffer(self_read, Some(secondary_bytes_to_read))?; - temp_buffer_drained.append(data.temp_buffer.drain(..secondary_bytes_to_read).collect()); + temp_buffer_drained.append(&mut data.temp_buffer.drain(..secondary_bytes_to_read).collect()); + bytes_read += secondary_bytes_to_read; } assert_eq!(buf.len(), temp_buffer_drained.len()); buf.clone_from_slice(&temp_buffer_drained); + + Ok(bytes_read) } } From ace2d9f329d72249b2251a2bbdd114824fe63ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 12:58:18 +0200 Subject: [PATCH 60/65] cargo fmt --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 30 +++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 1f5eac3af02..d8e270e5e8f 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -67,8 +67,11 @@ struct WasiPipeDataWithDestructor { } impl WasiPipeDataWithDestructor { - fn read_buffer(&mut self, read_cb: WasiConsoleIoReadCallback, max_read: Option) -> io::Result> { - + fn read_buffer( + &mut self, + read_cb: WasiConsoleIoReadCallback, + max_read: Option, + ) -> io::Result> { const BLOCK_SIZE: usize = 1024; let mut final_buf = Vec::new(); @@ -83,14 +86,18 @@ impl WasiPipeDataWithDestructor { } let mut temp_buffer = if cur_read + BLOCK_SIZE > max_read { - vec![0;max_read - cur_read] + vec![0; max_read - cur_read] } else { - vec![0;BLOCK_SIZE] + vec![0; BLOCK_SIZE] }; let result = unsafe { let ptr = temp_buffer.as_mut_ptr() as *mut c_char; - (read_cb)(self.data.as_mut_ptr() as *const c_void, ptr, temp_buffer.len()) + (read_cb)( + self.data.as_mut_ptr() as *const c_void, + ptr, + temp_buffer.len(), + ) }; if result < 0 { @@ -122,7 +129,6 @@ impl Drop for WasiPipeDataWithDestructor { } impl wasi_pipe_t { - fn get_data_mut( &self, op_id: &'static str, @@ -153,10 +159,9 @@ impl fmt::Debug for wasi_pipe_t { impl io::Read for wasi_pipe_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { - let self_read = self.read; let mut data = self.get_data_mut("read")?; - + // fill up buf by draining temp_buffer first, then read more bytes let bytes_to_read = data.temp_buffer.len().min(buf.len()); let mut temp_buffer_drained: Vec<_> = data.temp_buffer.drain(..bytes_to_read).collect(); @@ -167,7 +172,8 @@ impl io::Read for wasi_pipe_t { if buf.len() >= temp_buffer_drained.len() { let secondary_bytes_to_read = data.temp_buffer.len().min(buf.len()); data.read_buffer(self_read, Some(secondary_bytes_to_read))?; - temp_buffer_drained.append(&mut data.temp_buffer.drain(..secondary_bytes_to_read).collect()); + temp_buffer_drained + .append(&mut data.temp_buffer.drain(..secondary_bytes_to_read).collect()); bytes_read += secondary_bytes_to_read; } @@ -523,11 +529,7 @@ pub unsafe extern "C" fn wasi_pipe_delete_str(buf: *mut c_char) { let _ = CString::from_raw(buf); } -unsafe fn wasi_pipe_read_bytes_internal( - ptr: *const wasi_pipe_t, - buf: &mut Vec -) -> i64 { - +unsafe fn wasi_pipe_read_bytes_internal(ptr: *const wasi_pipe_t, buf: &mut Vec) -> i64 { use std::io::Read; const BLOCK_SIZE: usize = 1024; From 67d650146cd273f40042b9da444bfcc315cc993a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 13:00:45 +0200 Subject: [PATCH 61/65] cargo clippy --fix --- lib/api/tests/externals.rs | 40 +++++++++++------------ lib/api/tests/reference_types.rs | 10 +++--- lib/vm/src/memory.rs | 8 ++--- lib/wasi/tests/stdio.rs | 2 +- tests/integration/cli/tests/create_exe.rs | 4 +-- tests/integration/ios/tests/dylib.rs | 4 +-- tests/lib/compiler-test-derive/src/lib.rs | 2 +- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs index 5c17579a4ab..175f69befde 100644 --- a/lib/api/tests/externals.rs +++ b/lib/api/tests/externals.rs @@ -211,27 +211,27 @@ fn function_new() -> Result<(), String> { let mut store = Store::default(); let function = Function::new_typed(&mut store, || {}); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![], vec![]) ); let function = Function::new_typed(&mut store, |_a: i32| {}); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![Type::I32], vec![]) ); let function = Function::new_typed(&mut store, |_a: i32, _b: i64, _c: f32, _d: f64| {}); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]) ); let function = Function::new_typed(&mut store, || -> i32 { 1 }); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![], vec![Type::I32]) ); let function = Function::new_typed(&mut store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) }); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]) ); Ok(()) @@ -247,13 +247,13 @@ fn function_new_env() -> Result<(), String> { let env = FunctionEnv::new(&mut store, my_env); let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut| {}); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![], vec![]) ); let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut, _a: i32| {}); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![Type::I32], vec![]) ); let function = Function::new_typed_with_env( @@ -262,13 +262,13 @@ fn function_new_env() -> Result<(), String> { |_env: FunctionEnvMut, _a: i32, _b: i64, _c: f32, _d: f64| {}, ); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]) ); let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut| -> i32 { 1 }); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![], vec![Type::I32]) ); let function = Function::new_typed_with_env( @@ -277,7 +277,7 @@ fn function_new_env() -> Result<(), String> { |_env: FunctionEnvMut| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) }, ); assert_eq!( - function.ty(&mut store).clone(), + function.ty(&mut store), FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]) ); Ok(()) @@ -294,35 +294,35 @@ fn function_new_dynamic() -> Result<(), String> { &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); let function_type = FunctionType::new(vec![Type::I32], vec![]); let function = Function::new( &mut store, &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]); let function = Function::new( &mut store, &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); let function_type = FunctionType::new(vec![], vec![Type::I32]); let function = Function::new( &mut store, &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]); let function = Function::new( &mut store, &function_type, |_values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); // Using array signature let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]); @@ -356,7 +356,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); let function_type = FunctionType::new(vec![Type::I32], vec![]); let function = Function::new_with_env( &mut store, @@ -364,7 +364,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]); let function = Function::new_with_env( &mut store, @@ -372,7 +372,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); let function_type = FunctionType::new(vec![], vec![Type::I32]); let function = Function::new_with_env( &mut store, @@ -380,7 +380,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]); let function = Function::new_with_env( &mut store, @@ -388,7 +388,7 @@ fn function_new_dynamic_env() -> Result<(), String> { &function_type, |_env: FunctionEnvMut, _values: &[Value]| unimplemented!(), ); - assert_eq!(function.ty(&mut store).clone(), function_type); + assert_eq!(function.ty(&mut store), function_type); // Using array signature let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]); diff --git a/lib/api/tests/reference_types.rs b/lib/api/tests/reference_types.rs index aecd46d48ec..8746936f06f 100644 --- a/lib/api/tests/reference_types.rs +++ b/lib/api/tests/reference_types.rs @@ -367,7 +367,7 @@ pub mod reference_types { let global: &Global = instance.exports.get_global("global")?; { let er = ExternRef::new(&mut store, 3usize); - global.set(&mut store, Value::ExternRef(Some(er.clone())))?; + global.set(&mut store, Value::ExternRef(Some(er)))?; } let get_from_global: TypedFunction<(), Option> = instance .exports @@ -398,7 +398,7 @@ pub mod reference_types { let er = ExternRef::new(&mut store, 3usize); - let result = pass_extern_ref.call(&mut store, Some(er.clone())); + let result = pass_extern_ref.call(&mut store, Some(er)); assert!(result.is_err()); Ok(()) @@ -442,7 +442,7 @@ pub mod reference_types { let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 10_000)?; assert_eq!(result, -1); - let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 8)?; + let result = grow_table_with_ref.call(&mut store, Some(er1), 8)?; assert_eq!(result, 2); for i in 2..10 { @@ -454,7 +454,7 @@ pub mod reference_types { } { - fill_table_with_ref.call(&mut store, Some(er2.clone()), 0, 2)?; + fill_table_with_ref.call(&mut store, Some(er2), 0, 2)?; } { @@ -462,7 +462,7 @@ pub mod reference_types { table2.set(&mut store, 1, Value::ExternRef(Some(er3.clone())))?; table2.set(&mut store, 2, Value::ExternRef(Some(er3.clone())))?; table2.set(&mut store, 3, Value::ExternRef(Some(er3.clone())))?; - table2.set(&mut store, 4, Value::ExternRef(Some(er3.clone())))?; + table2.set(&mut store, 4, Value::ExternRef(Some(er3)))?; } { diff --git a/lib/vm/src/memory.rs b/lib/vm/src/memory.rs index f8b80d2cee4..056f73354d2 100644 --- a/lib/vm/src/memory.rs +++ b/lib/vm/src/memory.rs @@ -357,7 +357,7 @@ impl VMMemory { /// /// This creates a `Memory` with owned metadata: this can be used to create a memory /// that will be imported into Wasm modules. - pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result { + pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result { Ok(Self(Box::new(VMOwnedMemory::new(memory, style)?))) } @@ -372,7 +372,7 @@ impl VMMemory { memory: &MemoryType, style: &MemoryStyle, vm_memory_location: NonNull, - ) -> Result { + ) -> Result { Ok(Self(Box::new(VMOwnedMemory::from_definition( memory, style, @@ -384,9 +384,9 @@ impl VMMemory { /// are natively supported /// - VMOwnedMemory -> VMMemory /// - Box -> VMMemory - pub fn from_custom(memory: IntoVMMemory) -> VMMemory + pub fn from_custom(memory: IntoVMMemory) -> Self where - IntoVMMemory: Into, + IntoVMMemory: Into, { memory.into() } diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index 5c759d76c1a..fc29889ebc1 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -168,7 +168,7 @@ fn test_stdin() { // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); let result = start.call(&mut store, &[]); - assert!(!result.is_err()); + assert!(result.is_ok()); // We assure stdin is now empty let mut buf = Vec::new(); diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index 45969f7c69e..866bef6a5ae 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -277,7 +277,7 @@ fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> a let object_path = operating_dir.join("wasm.obj"); let output: Vec = WasmerCreateObj { - current_dir: operating_dir.clone(), + current_dir: operating_dir, wasm_path, output_object_path: object_path.clone(), compiler: Compiler::Cranelift, @@ -292,7 +292,7 @@ fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> a "create-obj successfully completed but object output file `{}` missing", object_path.display() ); - let mut object_header_path = object_path.clone(); + let mut object_header_path = object_path; object_header_path.set_extension("h"); assert!( object_header_path.exists(), diff --git a/tests/integration/ios/tests/dylib.rs b/tests/integration/ios/tests/dylib.rs index 7660a62e4aa..49ef85c06a9 100644 --- a/tests/integration/ios/tests/dylib.rs +++ b/tests/integration/ios/tests/dylib.rs @@ -40,9 +40,9 @@ mod tests { */ let command_success = command.status.success(); let test_success = !stderr.contains("** TEST FAILED **"); - let success = command_success && test_success; + - success + command_success && test_success } fn remove_existing_artificats() -> Output { diff --git a/tests/lib/compiler-test-derive/src/lib.rs b/tests/lib/compiler-test-derive/src/lib.rs index 79c5ecdff9e..c8a022cdb55 100644 --- a/tests/lib/compiler-test-derive/src/lib.rs +++ b/tests/lib/compiler-test-derive/src/lib.rs @@ -143,7 +143,7 @@ pub fn compiler_test(attrs: TokenStream, input: TokenStream) -> TokenStream { #llvm_compiler_test } }; - x.into() + x } #[cfg(test)] From ba5c1b8b7cbcfee78c2aa45f84747b7d5e2fddb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 14:26:13 +0200 Subject: [PATCH 62/65] Try fixing CI issue w. TokenStream --- lib/api/tests/externals.rs | 10 ++-------- tests/integration/ios/tests/dylib.rs | 1 - tests/lib/compiler-test-derive/src/lib.rs | 3 ++- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs index 175f69befde..f593c763b79 100644 --- a/lib/api/tests/externals.rs +++ b/lib/api/tests/externals.rs @@ -210,10 +210,7 @@ fn memory_grow() -> Result<(), String> { fn function_new() -> Result<(), String> { let mut store = Store::default(); let function = Function::new_typed(&mut store, || {}); - assert_eq!( - function.ty(&mut store), - FunctionType::new(vec![], vec![]) - ); + assert_eq!(function.ty(&mut store), FunctionType::new(vec![], vec![])); let function = Function::new_typed(&mut store, |_a: i32| {}); assert_eq!( function.ty(&mut store), @@ -246,10 +243,7 @@ fn function_new_env() -> Result<(), String> { let my_env = MyEnv {}; let env = FunctionEnv::new(&mut store, my_env); let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut| {}); - assert_eq!( - function.ty(&mut store), - FunctionType::new(vec![], vec![]) - ); + assert_eq!(function.ty(&mut store), FunctionType::new(vec![], vec![])); let function = Function::new_typed_with_env(&mut store, &env, |_env: FunctionEnvMut, _a: i32| {}); assert_eq!( diff --git a/tests/integration/ios/tests/dylib.rs b/tests/integration/ios/tests/dylib.rs index 49ef85c06a9..db452fffb60 100644 --- a/tests/integration/ios/tests/dylib.rs +++ b/tests/integration/ios/tests/dylib.rs @@ -40,7 +40,6 @@ mod tests { */ let command_success = command.status.success(); let test_success = !stderr.contains("** TEST FAILED **"); - command_success && test_success } diff --git a/tests/lib/compiler-test-derive/src/lib.rs b/tests/lib/compiler-test-derive/src/lib.rs index c8a022cdb55..684ab9c0eee 100644 --- a/tests/lib/compiler-test-derive/src/lib.rs +++ b/tests/lib/compiler-test-derive/src/lib.rs @@ -143,7 +143,8 @@ pub fn compiler_test(attrs: TokenStream, input: TokenStream) -> TokenStream { #llvm_compiler_test } }; - x + #[cfg(test)] + TokenStream::from(x) } #[cfg(test)] From 8951c9d571a5e163db28afcba892291991a67428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 14:33:00 +0200 Subject: [PATCH 63/65] Use into() instead of TokenStream::from --- tests/lib/compiler-test-derive/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/lib/compiler-test-derive/src/lib.rs b/tests/lib/compiler-test-derive/src/lib.rs index 684ab9c0eee..79c5ecdff9e 100644 --- a/tests/lib/compiler-test-derive/src/lib.rs +++ b/tests/lib/compiler-test-derive/src/lib.rs @@ -143,8 +143,7 @@ pub fn compiler_test(attrs: TokenStream, input: TokenStream) -> TokenStream { #llvm_compiler_test } }; - #[cfg(test)] - TokenStream::from(x) + x.into() } #[cfg(test)] From f6fa5b7cde9843d1e64dfd221b07dbeafa7479d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Fri, 14 Oct 2022 21:27:19 +0200 Subject: [PATCH 64/65] "config" -> "wasi_config" --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index d8e270e5e8f..5e7c34c75e1 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -636,7 +636,7 @@ pub unsafe extern "C" fn wasi_config_new( #[no_mangle] pub unsafe extern "C" fn wasi_config_env( - config: &mut wasi_config_t, + wasi_config: &mut wasi_config_t, key: *const c_char, value: *const c_char, ) { @@ -648,22 +648,22 @@ pub unsafe extern "C" fn wasi_config_env( let value_cstr = CStr::from_ptr(value); let value_bytes = value_cstr.to_bytes(); - config.state_builder.env(key_bytes, value_bytes); + wasi_config.state_builder.env(key_bytes, value_bytes); } #[no_mangle] -pub unsafe extern "C" fn wasi_config_arg(config: &mut wasi_config_t, arg: *const c_char) { +pub unsafe extern "C" fn wasi_config_arg(wasi_config: &mut wasi_config_t, arg: *const c_char) { debug_assert!(!arg.is_null()); let arg_cstr = CStr::from_ptr(arg); let arg_bytes = arg_cstr.to_bytes(); - config.state_builder.arg(arg_bytes); + wasi_config.state_builder.arg(arg_bytes); } #[no_mangle] pub unsafe extern "C" fn wasi_config_preopen_dir( - config: &mut wasi_config_t, + wasi_config: &mut wasi_config_t, dir: *const c_char, ) -> bool { let dir_cstr = CStr::from_ptr(dir); @@ -676,7 +676,7 @@ pub unsafe extern "C" fn wasi_config_preopen_dir( } }; - if let Err(e) = config.state_builder.preopen_dir(dir_str) { + if let Err(e) = wasi_config.state_builder.preopen_dir(dir_str) { update_last_error(e); return false; } @@ -686,7 +686,7 @@ pub unsafe extern "C" fn wasi_config_preopen_dir( #[no_mangle] pub unsafe extern "C" fn wasi_config_mapdir( - config: &mut wasi_config_t, + wasi_config: &mut wasi_config_t, alias: *const c_char, dir: *const c_char, ) -> bool { @@ -710,7 +710,7 @@ pub unsafe extern "C" fn wasi_config_mapdir( } }; - if let Err(e) = config.state_builder.map_dir(alias_str, dir_str) { + if let Err(e) = wasi_config.state_builder.map_dir(alias_str, dir_str) { update_last_error(e); return false; } @@ -719,33 +719,33 @@ pub unsafe extern "C" fn wasi_config_mapdir( } #[no_mangle] -pub extern "C" fn wasi_config_capture_stdout(config: &mut wasi_config_t) { - config.stdout = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); +pub extern "C" fn wasi_config_capture_stdout(wasi_config: &mut wasi_config_t) { + wasi_config.stdout = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] -pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) { - config.stdout = None; +pub extern "C" fn wasi_config_inherit_stdout(wasi_config: &mut wasi_config_t) { + wasi_config.stdout = None; } #[no_mangle] -pub extern "C" fn wasi_config_capture_stderr(config: &mut wasi_config_t) { - config.stderr = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); +pub extern "C" fn wasi_config_capture_stderr(wasi_config: &mut wasi_config_t) { + wasi_config.stderr = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] -pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) { - config.stderr = None; +pub extern "C" fn wasi_config_inherit_stderr(wasi_config: &mut wasi_config_t) { + wasi_config.stderr = None; } #[no_mangle] -pub extern "C" fn wasi_config_capture_stdin(config: &mut wasi_config_t) { - config.stdin = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); +pub extern "C" fn wasi_config_capture_stdin(wasi_config: &mut wasi_config_t) { + wasi_config.stdin = Some(unsafe { Box::from_raw(wasi_pipe_new_null()) }); } #[no_mangle] -pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { - config.stdin = None; +pub extern "C" fn wasi_config_inherit_stdin(wasi_config: &mut wasi_config_t) { + wasi_config.stdin = None; } #[no_mangle] @@ -791,24 +791,24 @@ pub struct wasi_env_t { #[no_mangle] pub unsafe extern "C" fn wasi_env_new( store: Option<&mut wasm_store_t>, - mut config: Box, + mut wasi_config: Box, ) -> Option> { let store = &mut store?.inner; let mut store_mut = store.store_mut(); - if let Some(stdout) = config.stdout { - config.state_builder.stdout(stdout); + if let Some(stdout) = wasi_config.stdout { + wasi_config.state_builder.stdout(stdout); } - if let Some(stderr) = config.stderr { - config.state_builder.stderr(stderr); + if let Some(stderr) = wasi_config.stderr { + wasi_config.state_builder.stderr(stderr); } - if let Some(stdin) = config.stdin { - config.state_builder.stdin(stdin); + if let Some(stdin) = wasi_config.stdin { + wasi_config.state_builder.stdin(stdin); } - let wasi_state = c_try!(config.state_builder.finalize(&mut store_mut)); + let wasi_state = c_try!(wasi_config.state_builder.finalize(&mut store_mut)); Some(Box::new(wasi_env_t { inner: wasi_state, From 05d74ea3fbabc0adcb0098d4896a623cc5a34ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Mon, 17 Oct 2022 13:51:10 +0200 Subject: [PATCH 65/65] Fix WASI pipe to properly store read bytes in temp_buffer --- lib/c-api/src/wasm_c_api/wasi/mod.rs | 93 +++++++++++++++++++--------- lib/wasi/src/state/pipe.rs | 26 +++++--- 2 files changed, 80 insertions(+), 39 deletions(-) diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 5e7c34c75e1..b83dc3fd243 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -58,6 +58,7 @@ pub struct wasi_pipe_t { data: Option>>>, } +#[derive(Debug)] struct WasiPipeDataWithDestructor { data: Vec, // Buffer of already-read data that is being read into, @@ -71,12 +72,17 @@ impl WasiPipeDataWithDestructor { &mut self, read_cb: WasiConsoleIoReadCallback, max_read: Option, - ) -> io::Result> { + ) -> io::Result { const BLOCK_SIZE: usize = 1024; let mut final_buf = Vec::new(); - let max_read = max_read.unwrap_or(usize::MAX); + let max_to_read = max_read.unwrap_or(usize::MAX); + let max_read = max_to_read.saturating_sub(self.temp_buffer.len()); + if max_read == 0 { + // there are n bytes being available to read in the temp_buffer + return Ok(max_to_read); + } let mut cur_read = 0; // Read bytes until either EOF is reached or max_read bytes are reached @@ -107,15 +113,28 @@ impl WasiPipeDataWithDestructor { )); } - if result == 0 { + let result = result as usize; + if result == 0 || result > temp_buffer.len() { break; // EOF } - cur_read += temp_buffer.len(); - final_buf.append(&mut temp_buffer); + cur_read += result; + final_buf.extend_from_slice(&temp_buffer[..result]); } - Ok(final_buf) + let final_buf_len = final_buf.len(); + + // store the bytes in temp_buffer + self.temp_buffer.extend_from_slice(&final_buf); + + // temp_buffer.len() can be smaller than max_read in case we + // encounter EOF earlier than expected + assert!(self.temp_buffer.len() <= max_read); + + // return how many bytes were just read + // + // caller has to clear temp_buffer to advance actual reading + Ok(final_buf_len) } } @@ -161,26 +180,11 @@ impl io::Read for wasi_pipe_t { fn read(&mut self, buf: &mut [u8]) -> io::Result { let self_read = self.read; let mut data = self.get_data_mut("read")?; - - // fill up buf by draining temp_buffer first, then read more bytes - let bytes_to_read = data.temp_buffer.len().min(buf.len()); - let mut temp_buffer_drained: Vec<_> = data.temp_buffer.drain(..bytes_to_read).collect(); - assert!(temp_buffer_drained.len() <= buf.len()); - - // If temp_buffer is exhausted, try reading the remaining bytes from the pipe - let mut bytes_read = bytes_to_read; - if buf.len() >= temp_buffer_drained.len() { - let secondary_bytes_to_read = data.temp_buffer.len().min(buf.len()); - data.read_buffer(self_read, Some(secondary_bytes_to_read))?; - temp_buffer_drained - .append(&mut data.temp_buffer.drain(..secondary_bytes_to_read).collect()); - bytes_read += secondary_bytes_to_read; - } - - assert_eq!(buf.len(), temp_buffer_drained.len()); - buf.clone_from_slice(&temp_buffer_drained); - - Ok(bytes_read) + let _ = data.read_buffer(self_read, Some(buf.len()))?; + let bytes_to_read = buf.len().min(data.temp_buffer.len()); + let bytes_read = data.temp_buffer.drain(..bytes_to_read).collect::>(); + buf[..bytes_read.len()].clone_from_slice(&bytes_read); + Ok(bytes_to_read) } } @@ -278,7 +282,7 @@ impl VirtualFile for wasi_pipe_t { fn bytes_available_read(&self) -> Result, FsError> { let self_read = self.read; let mut data = self.get_data_mut("bytes_available_read")?; - data.read_buffer(self_read, None)?; + let _ = data.read_buffer(self_read, None)?; Ok(Some(data.temp_buffer.len())) } fn bytes_available_write(&self) -> Result, FsError> { @@ -507,6 +511,36 @@ pub unsafe extern "C" fn wasi_pipe_flush(ptr: *mut wasi_pipe_t) -> i64 { } } +#[test] +fn test_wasi_pipe_with_destructor() { + let mut wasi_pipe_t_ptr = std::ptr::null_mut(); + let second_wasi_pipe_t_ptr = unsafe { wasi_pipe_new(&mut wasi_pipe_t_ptr) }; + let wasi_pipe_t_ptr = unsafe { &mut *wasi_pipe_t_ptr }; + let second_wasi_pipe_t_ptr = unsafe { &mut *second_wasi_pipe_t_ptr }; + + let data = b"hello".into_iter().map(|v| *v as i8).collect::>(); + let result = unsafe { wasi_pipe_write_bytes(wasi_pipe_t_ptr, data.as_ptr(), data.len()) }; + assert_eq!(result, 5); + + let bytes_avail = wasi_pipe_t_ptr.bytes_available_read(); + assert_eq!(bytes_avail, Ok(Some(0))); + + let bytes_avail2 = second_wasi_pipe_t_ptr.bytes_available_read(); + assert_eq!(bytes_avail2, Ok(Some(5))); + + let mut read_str_ptr = std::ptr::null_mut(); + let result = unsafe { wasi_pipe_read_str(second_wasi_pipe_t_ptr, &mut read_str_ptr) }; + assert_eq!(result, 6); // hello\0 + let buf_slice = unsafe { std::slice::from_raw_parts_mut(read_str_ptr, result as usize) }; + assert_eq!(buf_slice[..5], data); + + unsafe { + wasi_pipe_delete_str(read_str_ptr); + } + unsafe { wasi_pipe_delete(wasi_pipe_t_ptr) }; + unsafe { wasi_pipe_delete(second_wasi_pipe_t_ptr) }; +} + #[no_mangle] pub unsafe extern "C" fn wasi_pipe_read_bytes( ptr: *const wasi_pipe_t, @@ -553,12 +587,13 @@ unsafe fn wasi_pipe_read_bytes_internal(ptr: *const wasi_pipe_t, buf: &mut Vec i64 { +pub unsafe extern "C" fn wasi_pipe_read_str(ptr: *const wasi_pipe_t, buf: &mut *mut c_char) -> i64 { use std::ffi::CString; let mut target = Vec::new(); diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 70e41b249bd..60754a0cb0f 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -319,8 +319,6 @@ impl Read for WasiPipe { inner_buf.advance(read); return Ok(read); } - } else if !self.block { - return Ok(0); } } let rx = self.rx.lock().unwrap(); @@ -339,18 +337,26 @@ impl Read for WasiPipe { s } Err(_) => { - // could not immediately receive bytes, so we need to block - match rx.recv() { - Ok(o) => o, - // Errors can happen if the sender has been dropped already - // In this case, just return 0 to indicate that we can't read any - // bytes anymore - Err(_) => { - return Ok(0); + if !self.block { + // If self.block is explicitly set to false, never block + Vec::new() + } else { + // could not immediately receive bytes, so we need to block + match rx.recv() { + Ok(o) => o, + // Errors can happen if the sender has been dropped already + // In this case, just return 0 to indicate that we can't read any + // bytes anymore + Err(_) => { + return Ok(0); + } } } } }; + if data.is_empty() && self.read_buffer.as_ref().map(|s| s.len()).unwrap_or(0) == 0 { + return Ok(0); + } self.read_buffer.replace(Bytes::from(data)); } }