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 469921799..4ae701ca0 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -8,6 +8,7 @@ use super::{wasm_extern_t, wasm_memory_t, wasm_module_t, wasm_store_t}; // required due to really weird Rust resolution rules for macros // https://github.com/rust-lang/rust/issues/57966 use crate::c_try; +use crate::error::{update_last_error, CApiError}; use std::convert::TryFrom; use std::ffi::CStr; use std::os::raw::c_char; @@ -84,46 +85,6 @@ pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) { config.inherit_stdin = true; } -/* -// NOTE: don't modify this type without updating all users of it. We rely on -// this struct being `repr(transparent)` with `Box` in the API. -#[repr(transparent)] -pub struct wasi_file_handle_t { - inner: Box, -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_output_capturing_file_new() -> Box { - Box::new(wasi_file_handle_t { - inner: Box::new(capture_files::OutputCapturer::new()), - }) -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_file_handle_delete(_file_handle: Option>) {} - -/// returns the amount written to the buffer -#[no_mangle] -pub unsafe extern "C" fn wasi_output_capturing_file_read( - wasi_file: &mut wasi_file_handle_t, - buffer: *mut c_char, - buffer_len: usize, - start_offset: usize, -) -> isize { - let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len as usize); - if let Some(oc) = wasi_file - .inner - .downcast_ref::() - { - (&oc.buffer[start_offset..]) - .read(inner_buffer) - .unwrap_or_default() as isize - } else { - -1 - } -} -*/ - #[allow(non_camel_case_types)] #[repr(C)] pub struct wasi_env_t { @@ -166,15 +127,48 @@ pub unsafe extern "C" fn wasi_env_read_stdout( ) -> isize { let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len as usize); let mut state = env.inner.state_mut(); + let stdout = if let Ok(stdout) = state.fs.stdout_mut() { - // TODO: actually do error handling here before shipping - stdout.as_mut().unwrap() + if let Some(stdout) = stdout.as_mut() { + stdout + } else { + update_last_error(CApiError { + msg: "could not find a file handle for `stdout`".to_string(), + }); + return -1; + } } else { return -1; }; read_inner(stdout, inner_buffer) } +#[no_mangle] +pub unsafe extern "C" fn wasi_env_read_stderr( + env: &mut wasi_env_t, + buffer: *mut c_char, + buffer_len: usize, +) -> isize { + let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len as usize); + let mut state = env.inner.state_mut(); + let stderr = if let Ok(stderr) = state.fs.stderr_mut() { + if let Some(stderr) = stderr.as_mut() { + stderr + } else { + update_last_error(CApiError { + msg: "could not find a file handle for `stderr`".to_string(), + }); + return -1; + } + } else { + update_last_error(CApiError { + msg: "could not find a file handle for `stderr`".to_string(), + }); + return -1; + }; + read_inner(stderr, inner_buffer) +} + fn read_inner(wasi_file: &mut Box, inner_buffer: &mut [u8]) -> isize { if let Some(oc) = wasi_file.downcast_mut::() { let mut num_bytes_written = 0; @@ -188,18 +182,6 @@ fn read_inner(wasi_file: &mut Box, inner_buffer: &mut [u8]) -> isi } } -/* -/// returns a non-owning reference to stdout -#[no_mangle] -pub extern "C" fn wasi_state_get_stdout( - state: &wasi_state_t, -) -> Option<&Option> { - let inner: &Option> = c_try!(state.inner.fs.stdout()); - // This is correct because `wasi_file_handle_t` is `repr(transparent)` to `Box` - let temp = unsafe { mem::transmute::<_, &'static Option>(inner) }; - Some(temp) -}*/ - #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] #[allow(non_camel_case_types)] @@ -246,22 +228,29 @@ pub unsafe extern "C" fn wasi_get_imports( store: Option>, module: &wasm_module_t, wasi_env: &wasi_env_t, - version: wasi_version_t, ) -> Option]>> { let store_ptr = store?.cast::(); let store = store_ptr.as_ref(); - // TODO: - //let version = c_try!(WasiVersion::try_from(version)); - let version = WasiVersion::try_from(version).ok()?; + let version = c_try!( + get_wasi_version(&module.inner, false).ok_or_else(|| CApiError { + msg: "could not detect a WASI version on the given module".to_string(), + }) + ); let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); - // TODO: this is very inefficient due to all the allocation required let mut extern_vec = vec![]; for it in module.inner.imports() { - // TODO: return an error message here if it's not found - let export = import_object.resolve_by_name(it.module(), it.name())?; + let export = c_try!(import_object + .resolve_by_name(it.module(), it.name()) + .ok_or_else(|| CApiError { + msg: format!( + "Failed to resolve import \"{}\" \"{}\"", + it.module(), + it.name() + ), + })); let inner = Extern::from_export(store, export); extern_vec.push(Box::new(wasm_extern_t { instance: None, diff --git a/lib/c-api/tests/wasm-c-api-wasi.c b/lib/c-api/tests/wasm-c-api-wasi.c index d33942494..ab8563ce1 100644 --- a/lib/c-api/tests/wasm-c-api-wasi.c +++ b/lib/c-api/tests/wasm-c-api-wasi.c @@ -66,11 +66,10 @@ int main(int argc, const char* argv[]) { print_wasmer_error(); return 1; } - wasi_version_t version = wasi_get_wasi_version(module); // Instantiate. printf("Instantiating module...\n"); - const wasm_extern_t* const* imports = wasi_get_imports(store, module, wasi_env, version); + const wasm_extern_t* const* imports = wasi_get_imports(store, module, wasi_env); if (!imports) { printf("> Error getting WASI imports!\n"); print_wasmer_error(); diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index 1567ce607..9a2b3984d 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -8,7 +8,6 @@ #define own -// TODO: rewrite explanation // In order to use WASI, we need a `wasi_env_t`, but first we need to configure it with // a `wasi_config_t`. // @@ -66,20 +65,24 @@ void wasi_env_delete(own wasi_env_t*); // Get an array of imports that can be used to instantiate the given module. own const wasm_extern_t* own const* wasi_get_imports(wasm_store_t* store, wasm_module_t* module, - wasi_env_t* wasi_env, - wasi_version_t version); + wasi_env_t* wasi_env); // TODO: investigate removing this part of the API -// TODO: investigate removing the wasi_version stuff from the API // Set the memory in the `wasi_env_t` so that the WASI host functions can access WASI's memory. void wasi_env_set_memory(wasi_env_t*, const wasm_memory_t*); -// read from stdout: -// TODO: document this +// Read from WASI's buffered stdout if stdout has not been inherited with +// `wasi_config_inherit_stdout`. size_t wasi_env_read_stdout(wasi_env_t* env, char* buffer, size_t buffer_len); +// Read from WASI's buffered stderr if stdout has not been inherited with +// `wasi_config_inherit_stderr`. +size_t wasi_env_read_stderr(wasi_env_t* env, + char* buffer, + size_t buffer_len); + // Get the version of WASI needed by the given Wasm module. wasi_version_t wasi_get_wasi_version(wasm_module_t*);