diff --git a/lib/emscripten/emtests/test_execvp.c b/lib/emscripten/emtests/test_execvp.c new file mode 100644 index 000000000..402654721 --- /dev/null +++ b/lib/emscripten/emtests/test_execvp.c @@ -0,0 +1,17 @@ +#include +#include + +int main() { + char command[] = "touch"; + char arg1[] = "foo.txt"; + char* argv[3]; + argv[0] = command; + argv[1] = arg1; + argv[2] = 0; + + printf("_execvp\n"); + int result = execvp(command, argv); + // should not return, and not print this message + printf("error"); + return 0; +} diff --git a/lib/emscripten/emtests/test_execvp.out b/lib/emscripten/emtests/test_execvp.out new file mode 100644 index 000000000..5048f1e2c --- /dev/null +++ b/lib/emscripten/emtests/test_execvp.out @@ -0,0 +1 @@ +_execvp diff --git a/lib/emscripten/emtests/test_execvp.wasm b/lib/emscripten/emtests/test_execvp.wasm new file mode 100644 index 000000000..a0959cc56 Binary files /dev/null and b/lib/emscripten/emtests/test_execvp.wasm differ diff --git a/lib/emscripten/emtests/test_execvp_windows.c b/lib/emscripten/emtests/test_execvp_windows.c new file mode 100644 index 000000000..c3920a4fa --- /dev/null +++ b/lib/emscripten/emtests/test_execvp_windows.c @@ -0,0 +1,18 @@ +#include +#include + +int main() { + char command[] = "C:\\Windows\\System32\\cmd.exe"; + char arg1[] = "echo"; + char arg2[] = "foo"; + char* argv[4]; + argv[0] = command; + argv[1] = arg1; + argv[2] = arg2; + argv[3] = 0; + printf("_execvp\n"); + int result = execvp(command, argv); + // should not return, and not print this message + printf("error"); + return 0; +} diff --git a/lib/emscripten/emtests/test_execvp_windows.wasm b/lib/emscripten/emtests/test_execvp_windows.wasm new file mode 100644 index 000000000..ec3a210c5 Binary files /dev/null and b/lib/emscripten/emtests/test_execvp_windows.wasm differ diff --git a/lib/emscripten/src/exec.rs b/lib/emscripten/src/exec.rs new file mode 100644 index 000000000..8f95c20f8 --- /dev/null +++ b/lib/emscripten/src/exec.rs @@ -0,0 +1,40 @@ +use libc::execvp; +use std::cell::Cell; +use std::ffi::CString; +use wasmer_runtime_core::vm::Ctx; + +pub fn _execvp(ctx: &mut Ctx, command_name_offset: u32, argv_offset: u32) -> i32 { + // a single reference to re-use + let emscripten_memory = ctx.memory(0); + + // read command name as string + let command_name_string_vec: Vec = emscripten_memory.view() + [(command_name_offset as usize)..] + .iter() + .map(|cell| cell.get()) + .take_while(|&byte| byte != 0) + .collect(); + let command_name_string = CString::new(command_name_string_vec).unwrap(); + + // get the array of args + let mut argv: Vec<*const i8> = emscripten_memory.view()[((argv_offset / 4) as usize)..] + .iter() + .map(|cell: &Cell| cell.get()) + .take_while(|&byte| byte != 0) + .map(|offset| { + let p: *const i8 = (emscripten_memory.view::()[(offset as usize)..]) + .iter() + .map(|cell| cell.as_ptr() as *const i8) + .collect::>()[0]; + p + }) + .collect(); + + // push a nullptr on to the end of the args array + argv.push(std::ptr::null()); + + // construct raw pointers and hand them to `execvp` + let command_pointer = command_name_string.as_ptr() as *const i8; + let args_pointer = argv.as_ptr(); + unsafe { execvp(command_pointer, args_pointer) } +} diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 373ad51ab..cbcb5c1fc 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -31,6 +31,7 @@ mod emscripten_target; mod env; mod errno; mod exception; +mod exec; mod io; mod jmp; mod linking; @@ -439,6 +440,9 @@ pub fn generate_emscripten_env(globals: &mut EmscriptenGlobals) -> ImportObject "___unlock" => func!(crate::lock::___unlock), "___wait" => func!(crate::lock::___wait), + // exec + "_execvp" => func!(crate::exec::_execvp), + // Env "___assert_fail" => func!(crate::env::___assert_fail), "_getenv" => func!(crate::env::_getenv), diff --git a/lib/emscripten/tests/emtests/mod.rs b/lib/emscripten/tests/emtests/mod.rs index efedf0d6b..89a66bf2b 100644 --- a/lib/emscripten/tests/emtests/mod.rs +++ b/lib/emscripten/tests/emtests/mod.rs @@ -43,6 +43,7 @@ mod test_exceptions_2; mod test_exceptions_multi; mod test_exceptions_std; mod test_exceptions_white_list; +mod test_execvp; mod test_fast_math; mod test_flexarray_struct; mod test_float32_precise; diff --git a/lib/emscripten/tests/emtests/test_execvp.rs b/lib/emscripten/tests/emtests/test_execvp.rs new file mode 100644 index 000000000..c9b4b5113 --- /dev/null +++ b/lib/emscripten/tests/emtests/test_execvp.rs @@ -0,0 +1,17 @@ +#[test] +fn test_execvp() { + #[cfg(not(target_os = "windows"))] + assert_emscripten_output!( + "../../emtests/test_execvp.wasm", + "test_execvp", + vec![], + "../../emtests/test_execvp.out" + ); + #[cfg(target_os = "windows")] + assert_emscripten_output!( + "../../emtests/test_execvp_windows.wasm", + "test_execvp", + vec![], + "../../emtests/test_execvp.out" + ); +}