Fix crashing cli args

This commit is contained in:
Lachlan Sneff 2018-12-06 22:40:44 -05:00
parent 485da4c701
commit 0e024aa722
5 changed files with 72 additions and 44 deletions

View File

@ -19,7 +19,7 @@ mod utils;
mod varargs; mod varargs;
pub use self::storage::{align_memory, static_alloc}; 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? // TODO: Magic number - how is this calculated?
const TOTAL_STACK: u32 = 5242880; const TOTAL_STACK: u32 = 5242880;

View File

@ -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 { 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 s = CStr::from_ptr(cstr).to_str().unwrap();
let cstr_len = s.len(); 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 raw_memory = instance.memory_offset_addr(0, space_offset as _) as *mut u8;
let slice = slice::from_raw_parts_mut(raw_memory, cstr_len); 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 space_offset
} }
pub unsafe fn copy_cstr_into_wasm_stack(instance: &mut Instance, cstr: *const c_char) -> u32 { pub unsafe fn copy_cstr_array_into_wasm(array_count: u32, array: *mut *mut c_char, instance: &mut Instance) -> u32 {
let s = CStr::from_ptr(cstr).to_str().unwrap(); let array_offset = (instance.emscripten_data.as_ref().unwrap().malloc)((array_count as usize * size_of::<u32>()) as _, instance);
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;
space_offset space_offset
} }
@ -69,6 +59,25 @@ pub unsafe fn copy_cstr_array_into_wasm_stack(array_count: u32, array: *mut *mut
array_offset 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::<T>() 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( pub unsafe fn copy_terminated_array_of_cstrs(
_instance: &mut Instance, _instance: &mut Instance,
cstrs: *mut *mut c_char, cstrs: *mut *mut c_char,

View File

@ -7,7 +7,7 @@ use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::exit; 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 structopt::StructOpt;
use wasmer::*; use wasmer::*;
@ -91,7 +91,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
let main: extern "C" fn(u32, u32, &webassembly::Instance) = let main: extern "C" fn(u32, u32, &webassembly::Instance) =
get_instance_function!(instance, func_index); 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)); return call_protected!(main(argc, argv, &instance)).map_err(|err| format!("{}", err));
// TODO: We should implement emscripten __ATEXIT__ // TODO: We should implement emscripten __ATEXIT__
@ -128,36 +128,53 @@ fn main() {
} }
} }
fn get_module_arguments(options: &Run, instance: &mut webassembly::Instance) -> (u32, u32) { fn store_module_arguments(options: &Run, instance: &mut webassembly::Instance) -> (u32, u32) {
// Application Arguments let argc = options.args.len() + 1;
let mut arg_values: Vec<String> = Vec::new();
let mut arg_addrs: Vec<*const u8> = Vec::new();
let arg_length = options.args.len() + 1;
arg_values.reserve_exact(arg_length); let (argv_offset, argv_slice): (_, &mut [u32]) = unsafe { allocate_on_stack(((argc + 1) * 4) as u32, instance) };
arg_addrs.reserve_exact(arg_length); assert!(argv_slice.len() >= 1);
// Push name of wasm file argv_slice[0] = unsafe { allocate_cstr_on_stack(options.path.to_str().unwrap(), instance).0 };
arg_values.push(format!("{}\0", options.path.to_str().unwrap()));
arg_addrs.push(arg_values[0].as_ptr());
// Push additional arguments for (slot, arg) in argv_slice[1..argc].iter_mut().zip(options.args.iter()) {
for (i, arg) in options.args.iter().enumerate() { *slot = unsafe { allocate_cstr_on_stack(&arg, instance).0 };
arg_values.push(format!("{}\0", arg));
arg_addrs.push(arg_values[i + 1].as_ptr());
} }
// Get argument count and pointer to addresses argv_slice[argc] = 0;
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 (argc as u32, argv_offset)
let argv_offset = unsafe {
copy_cstr_array_into_wasm_stack(argc, argv, instance)
};
debug!("argc = {:?}", argc);
debug!("argv = {:?}", arg_addrs);
(argc, argv_offset)
} }
// fn get_module_arguments(options: &Run, instance: &mut webassembly::Instance) -> (u32, u32) {
// // Application Arguments
// let mut arg_values: Vec<String> = 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)
// }

View File

@ -74,7 +74,7 @@ pub struct EmscriptenData {
pub free: extern "C" fn(i32, &mut Instance), pub free: extern "C" fn(i32, &mut Instance),
pub memalign: extern "C" fn (u32, u32, &mut Instance) -> u32, pub memalign: extern "C" fn (u32, u32, &mut Instance) -> u32,
pub memset: extern "C" fn(u32, i32, 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 { impl fmt::Debug for EmscriptenData {

View File

@ -9,7 +9,7 @@ use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir::immediates::{Imm64, Offset32}; use cranelift_codegen::ir::immediates::{Imm64, Offset32};
use cranelift_codegen::ir::types::*; use cranelift_codegen::ir::types::*;
use cranelift_codegen::ir::{ 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_codegen::isa::{CallConv, TargetFrontendConfig};
use cranelift_entity::{EntityRef, PrimaryMap}; use cranelift_entity::{EntityRef, PrimaryMap};
@ -532,6 +532,8 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
mflags.set_aligned(); mflags.set_aligned();
let func_ptr = pos.ins().load(ptr, mflags, entry_addr, 0); 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, // Build a value list for the indirect call instruction containing the callee, call_args,
// and the vmctx parameter. // and the vmctx parameter.
let mut args = ir::ValueList::default(); let mut args = ir::ValueList::default();