From 0e024aa722523589f175fb338e9a49a5485d277a Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Thu, 6 Dec 2018 22:40:44 -0500 Subject: [PATCH] Fix crashing cli args --- src/apis/emscripten/mod.rs | 2 +- src/apis/emscripten/utils.rs | 35 ++++++++++------- src/bin/wasmer.rs | 73 ++++++++++++++++++++++-------------- src/webassembly/instance.rs | 2 +- src/webassembly/module.rs | 4 +- 5 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/apis/emscripten/mod.rs b/src/apis/emscripten/mod.rs index 81620df1b..374bb09b4 100644 --- a/src/apis/emscripten/mod.rs +++ b/src/apis/emscripten/mod.rs @@ -19,7 +19,7 @@ mod utils; mod varargs; pub use self::storage::{align_memory, static_alloc}; -pub use self::utils::{is_emscripten_module, copy_cstr_array_into_wasm_stack}; +pub use self::utils::{is_emscripten_module, copy_cstr_array_into_wasm, allocate_on_stack, allocate_cstr_on_stack}; // TODO: Magic number - how is this calculated? const TOTAL_STACK: u32 = 5242880; diff --git a/src/apis/emscripten/utils.rs b/src/apis/emscripten/utils.rs index 4f13c3f61..ad7d78675 100644 --- a/src/apis/emscripten/utils.rs +++ b/src/apis/emscripten/utils.rs @@ -20,7 +20,7 @@ pub fn is_emscripten_module(module: &Module) -> bool { pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) -> u32 { let s = CStr::from_ptr(cstr).to_str().unwrap(); let cstr_len = s.len(); - let space_offset = (instance.emscripten_data.as_ref().unwrap().malloc)(cstr_len as _, instance); + let space_offset = (instance.emscripten_data.as_ref().unwrap().malloc)((cstr_len as i32) + 1, instance); let raw_memory = instance.memory_offset_addr(0, space_offset as _) as *mut u8; let slice = slice::from_raw_parts_mut(raw_memory, cstr_len); @@ -33,18 +33,8 @@ pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) space_offset } -pub unsafe fn copy_cstr_into_wasm_stack(instance: &mut Instance, cstr: *const c_char) -> u32 { - let s = CStr::from_ptr(cstr).to_str().unwrap(); - let cstr_len = s.len(); - let space_offset = (instance.emscripten_data.as_ref().unwrap().stack_alloc)((cstr_len as u32) + 1, instance); - let raw_memory = instance.memory_offset_addr(0, space_offset as _) as *mut u8; - let slice = slice::from_raw_parts_mut(raw_memory, cstr_len); - - for (byte, loc) in s.bytes().zip(slice.iter_mut()) { - *loc = byte; - } - - *raw_memory.add(cstr_len) = 0; +pub unsafe fn copy_cstr_array_into_wasm(array_count: u32, array: *mut *mut c_char, instance: &mut Instance) -> u32 { + let array_offset = (instance.emscripten_data.as_ref().unwrap().malloc)((array_count as usize * size_of::()) as _, instance); space_offset } @@ -69,6 +59,25 @@ pub unsafe fn copy_cstr_array_into_wasm_stack(array_count: u32, array: *mut *mut array_offset } +pub unsafe fn allocate_on_stack<'a, T: Copy>(count: u32, instance: &'a Instance) -> (u32, &'a mut [T]) { + let offset = (instance.emscripten_data.as_ref().unwrap().stack_alloc)(count * (size_of::() as u32), instance); + let addr = instance.memory_offset_addr(0, offset as _) as *mut T; + let slice = slice::from_raw_parts_mut(addr, count as usize); + + (offset, slice) +} + +pub unsafe fn allocate_cstr_on_stack<'a>(s: &str, instance: &'a Instance) -> (u32, &'a [u8]) { + let (offset, slice) = allocate_on_stack((s.len() + 1) as u32, instance); + + use std::iter; + for (byte, loc) in s.bytes().chain(iter::once(0)).zip(slice.iter_mut()) { + *loc = byte; + } + + (offset, slice) +} + pub unsafe fn copy_terminated_array_of_cstrs( _instance: &mut Instance, cstrs: *mut *mut c_char, diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 932cdd37c..e15ef0d7c 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -7,7 +7,7 @@ use std::io::Read; use std::path::PathBuf; use std::process::exit; -use apis::emscripten::copy_cstr_array_into_wasm_stack; +use apis::emscripten::{allocate_on_stack, allocate_cstr_on_stack}; use structopt::StructOpt; use wasmer::*; @@ -91,7 +91,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { let main: extern "C" fn(u32, u32, &webassembly::Instance) = get_instance_function!(instance, func_index); - let (argc, argv) = get_module_arguments(options, &mut instance); + let (argc, argv) = store_module_arguments(options, &mut instance); return call_protected!(main(argc, argv, &instance)).map_err(|err| format!("{}", err)); // TODO: We should implement emscripten __ATEXIT__ @@ -128,36 +128,53 @@ fn main() { } } -fn get_module_arguments(options: &Run, instance: &mut webassembly::Instance) -> (u32, u32) { - // Application Arguments - let mut arg_values: Vec = Vec::new(); - let mut arg_addrs: Vec<*const u8> = Vec::new(); - let arg_length = options.args.len() + 1; +fn store_module_arguments(options: &Run, instance: &mut webassembly::Instance) -> (u32, u32) { + let argc = options.args.len() + 1; - arg_values.reserve_exact(arg_length); - arg_addrs.reserve_exact(arg_length); + let (argv_offset, argv_slice): (_, &mut [u32]) = unsafe { allocate_on_stack(((argc + 1) * 4) as u32, instance) }; + assert!(argv_slice.len() >= 1); - // Push name of wasm file - arg_values.push(format!("{}\0", options.path.to_str().unwrap())); - arg_addrs.push(arg_values[0].as_ptr()); + argv_slice[0] = unsafe { allocate_cstr_on_stack(options.path.to_str().unwrap(), instance).0 }; - // Push additional arguments - for (i, arg) in options.args.iter().enumerate() { - arg_values.push(format!("{}\0", arg)); - arg_addrs.push(arg_values[i + 1].as_ptr()); + for (slot, arg) in argv_slice[1..argc].iter_mut().zip(options.args.iter()) { + *slot = unsafe { allocate_cstr_on_stack(&arg, instance).0 }; } - // Get argument count and pointer to addresses - let argv = arg_addrs.as_ptr() as *mut *mut i8; - let argc = arg_length as u32; + argv_slice[argc] = 0; - // Copy the the arguments into the wasm memory and get offset - let argv_offset = unsafe { - copy_cstr_array_into_wasm_stack(argc, argv, instance) - }; - - debug!("argc = {:?}", argc); - debug!("argv = {:?}", arg_addrs); - - (argc, argv_offset) + (argc as u32, argv_offset) } + +// fn get_module_arguments(options: &Run, instance: &mut webassembly::Instance) -> (u32, u32) { +// // Application Arguments +// let mut arg_values: Vec = Vec::new(); +// let mut arg_addrs: Vec<*const u8> = Vec::new(); +// let arg_length = options.args.len() + 1; + +// arg_values.reserve_exact(arg_length); +// arg_addrs.reserve_exact(arg_length); + +// // Push name of wasm file +// arg_values.push(format!("{}\0", options.path.to_str().unwrap())); +// arg_addrs.push(arg_values[0].as_ptr()); + +// // Push additional arguments +// for (i, arg) in options.args.iter().enumerate() { +// arg_values.push(format!("{}\0", arg)); +// arg_addrs.push(arg_values[i + 1].as_ptr()); +// } + +// // Get argument count and pointer to addresses +// let argv = arg_addrs.as_ptr() as *mut *mut i8; +// let argc = arg_length as u32; + +// // Copy the the arguments into the wasm memory and get offset +// let argv_offset = unsafe { +// copy_cstr_array_into_wasm(argc, argv, instance) +// }; + +// debug!("argc = {:?}", argc); +// debug!("argv = {:?}", arg_addrs); + +// (argc, argv_offset) +// } diff --git a/src/webassembly/instance.rs b/src/webassembly/instance.rs index c68b33968..405345d0e 100644 --- a/src/webassembly/instance.rs +++ b/src/webassembly/instance.rs @@ -74,7 +74,7 @@ pub struct EmscriptenData { pub free: extern "C" fn(i32, &mut Instance), pub memalign: extern "C" fn (u32, u32, &mut Instance) -> u32, pub memset: extern "C" fn(u32, i32, u32, &mut Instance) -> u32, - pub stack_alloc: extern "C" fn (u32, &mut Instance) -> u32, + pub stack_alloc: extern "C" fn (u32, &Instance) -> u32, } impl fmt::Debug for EmscriptenData { diff --git a/src/webassembly/module.rs b/src/webassembly/module.rs index e6e32c627..b15fd8697 100644 --- a/src/webassembly/module.rs +++ b/src/webassembly/module.rs @@ -9,7 +9,7 @@ use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::ir::immediates::{Imm64, Offset32}; use cranelift_codegen::ir::types::*; use cranelift_codegen::ir::{ - self, AbiParam, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, InstBuilder, Signature, + self, AbiParam, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, InstBuilder, Signature, TrapCode, }; use cranelift_codegen::isa::{CallConv, TargetFrontendConfig}; use cranelift_entity::{EntityRef, PrimaryMap}; @@ -532,6 +532,8 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> { mflags.set_aligned(); let func_ptr = pos.ins().load(ptr, mflags, entry_addr, 0); + pos.ins().trapz(func_ptr, TrapCode::IndirectCallToNull); + // Build a value list for the indirect call instruction containing the callee, call_args, // and the vmctx parameter. let mut args = ir::ValueList::default();