From cc3f04efd74836b23c2ffe17ea00696d84e65052 Mon Sep 17 00:00:00 2001 From: Mackenzie Clark Date: Tue, 12 Mar 2019 10:48:33 -0700 Subject: [PATCH] expose vfs in emscripten and impl `read` syscall, feature flag --- Cargo.toml | 2 +- lib/emscripten/Cargo.toml | 6 ++- lib/emscripten/emtests/test_vfs.c | 12 ++++++ lib/emscripten/emtests/test_vfs.md | 6 +++ lib/emscripten/emtests/test_vfs.out | 1 + lib/emscripten/emtests/test_vfs.wasm | Bin 0 -> 46118 bytes lib/emscripten/src/lib.rs | 26 ++++++++++++- lib/emscripten/src/syscalls/mod.rs | 45 +++++++++++++++++++++-- lib/emscripten/src/syscalls/unix.rs | 1 + lib/emscripten/src/syscalls/windows.rs | 2 + lib/emscripten/tests/emtests/mod.rs | 2 + lib/emscripten/tests/emtests/test_vfs.rs | 9 +++++ 12 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 lib/emscripten/emtests/test_vfs.c create mode 100644 lib/emscripten/emtests/test_vfs.md create mode 100644 lib/emscripten/emtests/test_vfs.out create mode 100644 lib/emscripten/emtests/test_vfs.wasm create mode 100644 lib/emscripten/tests/emtests/test_vfs.rs diff --git a/Cargo.toml b/Cargo.toml index f404a19b2..efa0bec15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ glob = "0.2.11" [features] default = ["fast-tests"] - +vfs = ["wasmer-runtime-abi", "wasmer-runtime-core/vfs", "wasmer-emscripten/vfs", "wasmer-clif-backend/vfs"] debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] # This feature will allow cargo test to run much faster fast-tests = [] diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index cd691e566..b410582f3 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -10,6 +10,8 @@ build = "build/mod.rs" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" } +wasmer-runtime-abi = { path = "../runtime-abi", optional = true } lazy_static = "1.2.0" libc = "0.2.49" byteorder = "1" @@ -19,7 +21,6 @@ time = "0.1.41" rand = "0.6" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend", version = "0.2.0" } wabt = "0.7.2" [target.'cfg(not(windows))'.dev-dependencies] @@ -30,4 +31,5 @@ glob = "0.2.11" [features] clif = [] -llvm = [] \ No newline at end of file +llvm = [] +vfs = ["wasmer-runtime-core/vfs", "wasmer-clif-backend/vfs", "wasmer-runtime-abi"] diff --git a/lib/emscripten/emtests/test_vfs.c b/lib/emscripten/emtests/test_vfs.c new file mode 100644 index 000000000..e7fc5c129 --- /dev/null +++ b/lib/emscripten/emtests/test_vfs.c @@ -0,0 +1,12 @@ +#include +#include +#include + +int main() { + char data[256] = {0}; + ssize_t fd = open("data.txt", 0); + ssize_t result = read((int)fd, &data, 255); + printf("content: %s", data); + printf("fd: %zd\n", fd); + return 0; +} diff --git a/lib/emscripten/emtests/test_vfs.md b/lib/emscripten/emtests/test_vfs.md new file mode 100644 index 000000000..e399c8138 --- /dev/null +++ b/lib/emscripten/emtests/test_vfs.md @@ -0,0 +1,6 @@ +The wasm file `test_vfs.wasm` is generated by compiling the `test_vfs.c` and writing a tar.zst blob with a single file +named `data.txt`. + +The program expects to find a file named `data.txt` and reads the contents and the file descriptor. + +The runtime should mount the virtual filesystem and expose the file. \ No newline at end of file diff --git a/lib/emscripten/emtests/test_vfs.out b/lib/emscripten/emtests/test_vfs.out new file mode 100644 index 000000000..5d8528aff --- /dev/null +++ b/lib/emscripten/emtests/test_vfs.out @@ -0,0 +1 @@ +content: wasmer is awesomer \ No newline at end of file diff --git a/lib/emscripten/emtests/test_vfs.wasm b/lib/emscripten/emtests/test_vfs.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8456c3f046a97080e6ef36d3729dd19e5d12086d GIT binary patch literal 46118 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 literal 0 HcmV?d00001 diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 66d9b75ff..fd82f07ca 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -54,6 +54,11 @@ pub use self::utils::{ get_emscripten_table_size, is_emscripten_module, }; +use std::fs::File; +use std::io::Write; +#[cfg(feature = "vfs")] +use wasmer_runtime_abi::vfs::vfs::VfsBacking; + // TODO: Magic number - how is this calculated? const TOTAL_STACK: u32 = 5_242_880; // TODO: Magic number - how is this calculated? @@ -135,6 +140,9 @@ pub struct EmscriptenData<'a> { pub dyn_call_viji: Option>, pub dyn_call_vijiii: Option>, pub dyn_call_vijj: Option>, + + #[cfg(feature = "vfs")] + pub vfs: Option, } impl<'a> EmscriptenData<'a> { @@ -231,17 +239,33 @@ impl<'a> EmscriptenData<'a> { dyn_call_viji, dyn_call_vijiii, dyn_call_vijj, + #[cfg(feature = "vfs")] + vfs: None, } } } pub fn run_emscripten_instance( - _module: &Module, + module: &Module, instance: &mut Instance, path: &str, args: Vec<&str>, ) -> CallResult<()> { let mut data = EmscriptenData::new(instance); + + // Construct a new virtual filesystem and inject it into the emscripten data + // This is behind a feature flag for now, but will be default in the future + #[cfg(feature = "vfs")] + { + data.vfs = match module.info().custom_sections.get("wasmer_fs") { + Some(bytes) => match VfsBacking::from_tar_zstd_bytes(&bytes[..]) { + Ok(vfs_backing) => Some(vfs_backing), + Err(_) => None, + }, + None => None, + }; + } + let data_ptr = &mut data as *mut _ as *mut c_void; instance.context_mut().data = data_ptr; diff --git a/lib/emscripten/src/syscalls/mod.rs b/lib/emscripten/src/syscalls/mod.rs index 39bd2750d..fe16295f5 100644 --- a/lib/emscripten/src/syscalls/mod.rs +++ b/lib/emscripten/src/syscalls/mod.rs @@ -29,7 +29,7 @@ use libc::{ // iovec, lseek, // open, - read, + // read, // readv, rmdir, // writev, @@ -40,7 +40,6 @@ use libc::{ use wasmer_runtime_core::vm::Ctx; use super::env; -use std::cell::Cell; use std::slice; // use std::sys::fd::FileDesc; @@ -67,6 +66,7 @@ pub fn ___syscall1(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) { } /// read +#[cfg(not(feature = "vfs"))] pub fn ___syscall3(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 { // -> ssize_t debug!("emscripten::___syscall3 (read) {}", which); @@ -75,7 +75,27 @@ pub fn ___syscall3(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 { let count: i32 = varargs.get(ctx); debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count); let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void; - let ret = unsafe { read(fd, buf_addr, count as _) }; + let ret = unsafe { libc::read(fd, buf_addr, count as _) }; + debug!("=> ret: {}", ret); + ret as _ +} + +/// read +#[cfg(feature = "vfs")] +pub fn ___syscall3(ctx: &mut Ctx, which: i32, mut varargs: VarArgs) -> i32 { + // -> ssize_t + debug!("emscripten::___syscall3 (read - vfs) {}", which); + let fd: i32 = varargs.get(ctx); + let buf: u32 = varargs.get(ctx); + let count: i32 = varargs.get(ctx); + debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count); + let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut u8; + let mut buf_slice = unsafe { slice::from_raw_parts_mut(buf_addr, count as _) }; + let emscripten_data = get_emscripten_data(ctx); + let ret = match &mut emscripten_data.vfs { + Some(vfs) => vfs.read_file(fd as _, &mut buf_slice).unwrap(), + None => 0, + }; debug!("=> ret: {}", ret); ret as _ } @@ -91,6 +111,23 @@ pub fn ___syscall4(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { unsafe { write(fd, buf_addr, count as _) as i32 } } +/// open +#[cfg(feature = "vfs")] +pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { + debug!("emscripten::___syscall5 (open vfs) {}", which); + let pathname: u32 = varargs.get(ctx); + let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; + let path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() }; + let emscripten_data = get_emscripten_data(ctx); + let fd = if let Some(vfs) = &mut emscripten_data.vfs { + vfs.open_file(path_str).unwrap_or(-1) + } else { + -1 + }; + debug!("=> fd: {}", fd); + return fd as _; +} + /// close pub fn ___syscall6(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall6 (close) {}", which); @@ -307,7 +344,7 @@ pub fn ___syscall145(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> i32 { as *mut c_void; let iov_len = (*guest_iov_addr).iov_len as _; // debug!("=> iov_addr: {:?}, {:?}", iov_base, iov_len); - let curr = read(fd, iov_base, iov_len); + let curr = libc::read(fd, iov_base, iov_len); if curr < 0 { return -1; } diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index a73456d09..5d4aff3c9 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -78,6 +78,7 @@ use libc::SO_NOSIGPIPE; const SO_NOSIGPIPE: c_int = 0; /// open +#[cfg(not(feature = "vfs"))] pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall5 (open) {}", which); let pathname: u32 = varargs.get(ctx); diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index d2584bbd4..c797a3d43 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -1,3 +1,4 @@ +use crate::env::get_emscripten_data; use crate::utils::copy_cstr_into_wasm; use crate::utils::read_string_from_wasm; use crate::varargs::VarArgs; @@ -15,6 +16,7 @@ use wasmer_runtime_core::vm::Ctx; type pid_t = c_int; /// open +#[cfg(not(feature = "vfs"))] pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall5 (open) {}", which); let pathname: u32 = varargs.get(ctx); diff --git a/lib/emscripten/tests/emtests/mod.rs b/lib/emscripten/tests/emtests/mod.rs index 89a66bf2b..76983c05c 100644 --- a/lib/emscripten/tests/emtests/mod.rs +++ b/lib/emscripten/tests/emtests/mod.rs @@ -176,6 +176,8 @@ mod test_unary_literal; mod test_utf; mod test_varargs; mod test_varargs_multi; +#[cfg(feature = "vfs")] +mod test_vfs; mod test_vprintf; mod test_vsnprintf; mod test_wprintf; diff --git a/lib/emscripten/tests/emtests/test_vfs.rs b/lib/emscripten/tests/emtests/test_vfs.rs new file mode 100644 index 000000000..091086e19 --- /dev/null +++ b/lib/emscripten/tests/emtests/test_vfs.rs @@ -0,0 +1,9 @@ +#[test] +fn test_vfs() { + assert_emscripten_output!( + "../../emtests/test_vfs.wasm", + "test_vfs", + vec![], + "../../emtests/test_vfs.out" + ); +}