Skip to content

Commit

Permalink
add execvp
Browse files Browse the repository at this point in the history
  • Loading branch information
xmclark committed Mar 4, 2019
1 parent 2ea9d0b commit 00e3ec1
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 0 deletions.
17 changes: 17 additions & 0 deletions lib/emscripten/emtests/test_execvp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <stdio.h>
#include <unistd.h>

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;
}
1 change: 1 addition & 0 deletions lib/emscripten/emtests/test_execvp.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_execvp
Binary file added lib/emscripten/emtests/test_execvp.wasm
Binary file not shown.
18 changes: 18 additions & 0 deletions lib/emscripten/emtests/test_execvp_windows.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <stdio.h>
#include <unistd.h>

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;
}
Binary file added lib/emscripten/emtests/test_execvp_windows.wasm
Binary file not shown.
40 changes: 40 additions & 0 deletions lib/emscripten/src/exec.rs
Original file line number Diff line number Diff line change
@@ -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<u8> = 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<u32>| cell.get())
.take_while(|&byte| byte != 0)
.map(|offset| {
let p: *const i8 = (emscripten_memory.view::<u8>()[(offset as usize)..])
.iter()
.map(|cell| cell.as_ptr() as *const i8)
.collect::<Vec<*const i8>>()[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) }
}
4 changes: 4 additions & 0 deletions lib/emscripten/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ mod emscripten_target;
mod env;
mod errno;
mod exception;
mod exec;
mod io;
mod jmp;
mod linking;
Expand Down Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions lib/emscripten/tests/emtests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
17 changes: 17 additions & 0 deletions lib/emscripten/tests/emtests/test_execvp.rs
Original file line number Diff line number Diff line change
@@ -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"
);
}

0 comments on commit 00e3ec1

Please sign in to comment.