Fix execute after free issue with llvm (and presumably cranelift?)

This commit is contained in:
Lachlan Sneff
2019-03-04 14:41:56 -08:00
parent 039ebdcf75
commit 7ef2c0dece
6 changed files with 88 additions and 48 deletions

View File

@ -278,7 +278,7 @@ impl LLVMBackend {
info: &ModuleInfo, info: &ModuleInfo,
local_func_index: LocalFuncIndex, local_func_index: LocalFuncIndex,
) -> Option<NonNull<vm::Func>> { ) -> Option<NonNull<vm::Func>> {
let index = local_func_index.index(); let index = info.imported_functions.len() + local_func_index.index();
let name = if cfg!(target_os = "macos") { let name = if cfg!(target_os = "macos") {
format!("_fn{}", index) format!("_fn{}", index)
} else { } else {

View File

@ -136,6 +136,8 @@ pub fn parse_function_bodies(
pass_manager.add_aggressive_dce_pass(); pass_manager.add_aggressive_dce_pass();
pass_manager.run_on_module(&module); pass_manager.run_on_module(&module);
// module.print_to_stderr();
Ok((module, intrinsics)) Ok((module, intrinsics))
} }
@ -671,15 +673,11 @@ fn parse_function(
let func_ptr_ty = llvm_sig.ptr_type(AddressSpace::Generic); let func_ptr_ty = llvm_sig.ptr_type(AddressSpace::Generic);
// Once we can just bitcast between pointer types, remove this. let func_ptr = builder.build_pointer_cast(
let func_ptr = {
let ptr_int = builder.build_ptr_to_int(
func_ptr_untyped, func_ptr_untyped,
intrinsics.i64_ty, func_ptr_ty,
"func_ptr_int", "typed_func_ptr",
); );
builder.build_int_to_ptr(ptr_int, func_ptr_ty, "typed_func_ptr")
};
builder.build_call(func_ptr, &params, &state.var_name()) builder.build_call(func_ptr, &params, &state.var_name())
} }

View File

@ -197,7 +197,6 @@ impl Intrinsics {
.ptr_type(AddressSpace::Generic) .ptr_type(AddressSpace::Generic)
.as_basic_type_enum(), .as_basic_type_enum(),
imported_func_ty imported_func_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic) .ptr_type(AddressSpace::Generic)
.as_basic_type_enum(), .as_basic_type_enum(),
sigindex_ty sigindex_ty
@ -713,16 +712,13 @@ impl<'a> CtxType<'a> {
.build_load(func_array_ptr_ptr, "func_array_ptr") .build_load(func_array_ptr_ptr, "func_array_ptr")
.into_pointer_value(); .into_pointer_value();
let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false); let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false);
let imported_func_ptr_ptr = unsafe { let imported_func_ptr = unsafe {
cache_builder.build_in_bounds_gep( cache_builder.build_in_bounds_gep(
func_array_ptr, func_array_ptr,
&[const_index], &[const_index],
"imported_func_ptr_ptr", "imported_func_ptr",
) )
}; };
let imported_func_ptr = cache_builder
.build_load(imported_func_ptr_ptr, "imported_func_ptr")
.into_pointer_value();
let (func_ptr_ptr, ctx_ptr_ptr) = unsafe { let (func_ptr_ptr, ctx_ptr_ptr) = unsafe {
( (
cache_builder.build_struct_gep(imported_func_ptr, 0, "func_ptr_ptr"), cache_builder.build_struct_gep(imported_func_ptr, 0, "func_ptr_ptr"),

View File

@ -1,5 +1,9 @@
use crate::export::Export; use crate::export::Export;
use hashbrown::{hash_map::Entry, HashMap}; use hashbrown::{hash_map::Entry, HashMap};
use std::{
cell::{Ref, RefCell},
rc::Rc,
};
pub trait LikeNamespace { pub trait LikeNamespace {
fn get_export(&self, name: &str) -> Option<Export>; fn get_export(&self, name: &str) -> Option<Export>;
@ -37,14 +41,14 @@ impl IsExport for Export {
/// } /// }
/// ``` /// ```
pub struct ImportObject { pub struct ImportObject {
map: HashMap<String, Box<dyn LikeNamespace>>, map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>,
} }
impl ImportObject { impl ImportObject {
/// Create a new `ImportObject`. /// Create a new `ImportObject`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
map: HashMap::new(), map: Rc::new(RefCell::new(HashMap::new())),
} }
} }
@ -67,7 +71,9 @@ impl ImportObject {
S: Into<String>, S: Into<String>,
N: LikeNamespace + 'static, N: LikeNamespace + 'static,
{ {
match self.map.entry(name.into()) { let mut map = self.map.borrow_mut();
match map.entry(name.into()) {
Entry::Vacant(empty) => { Entry::Vacant(empty) => {
empty.insert(Box::new(namespace)); empty.insert(Box::new(namespace));
None None
@ -76,8 +82,20 @@ impl ImportObject {
} }
} }
pub fn get_namespace(&self, namespace: &str) -> Option<&(dyn LikeNamespace + 'static)> { pub fn get_namespace(&self, namespace: &str) -> Option<Ref<dyn LikeNamespace + 'static>> {
self.map.get(namespace).map(|namespace| &**namespace) let map_ref = self.map.borrow();
if map_ref.contains_key(namespace) {
Some(Ref::map(map_ref, |map| &*map[namespace]))
} else {
None
}
}
pub fn clone_ref(&self) -> Self {
Self {
map: Rc::clone(&self.map),
}
} }
} }

View File

@ -39,6 +39,8 @@ impl Drop for InstanceInner {
pub struct Instance { pub struct Instance {
module: Arc<ModuleInner>, module: Arc<ModuleInner>,
inner: Box<InstanceInner>, inner: Box<InstanceInner>,
#[allow(dead_code)]
import_object: ImportObject,
} }
impl Instance { impl Instance {
@ -64,7 +66,11 @@ impl Instance {
*inner.vmctx = vm::Ctx::new(&mut inner.backing, &mut inner.import_backing, &module) *inner.vmctx = vm::Ctx::new(&mut inner.backing, &mut inner.import_backing, &module)
}; };
let instance = Instance { module, inner }; let instance = Instance {
module,
inner,
import_object: imports.clone_ref(),
};
if let Some(start_index) = instance.module.info.start_func { if let Some(start_index) = instance.module.info.start_func {
instance.call_with_index(start_index, &[])?; instance.call_with_index(start_index, &[])?;

View File

@ -1,53 +1,75 @@
use wasmer_runtime::{compile, error, imports, Func, Value}; use wasmer_runtime::{compile, error, imports, Ctx, Func, Value};
use wabt::wat2wasm; use wabt::wat2wasm;
static WAT: &'static str = r#" static WAT: &'static str = r#"
(module (module
(type (;0;) (func (result i32))) (type (;0;) (func))
(type (;1;) (func (param i32 i32))) (type (;1;) (func))
(type (;2;) (func (param i32) (result i32))) (type (;2;) (func))
(func (;0;) (type 0) (result i32) (type (;3;) (func (result i32)))
memory.size (type (;4;) (func (result i32)))
i32.const 65536 (type (;5;) (func (param i32) (result i32)))
i32.mul) (type (;6;) (func (param i32)))
(func (;1;) (type 1) (param i32 i32) (import "spectest" "print_i32" (func (;0;) (type 6)))
call 0 (func (;1;) (type 0))
(func (;2;) (type 1))
(func (;3;) (type 4) (result i32)
i32.const 13)
(func (;4;) (type 5) (param i32) (result i32)
local.get 0 local.get 0
i32.sub i32.const 1
local.get 1 i32.add)
i32.store) (func (;5;) (type 5) (param i32) (result i32)
(func (;2;) (type 2) (param i32) (result i32)
call 0
local.get 0 local.get 0
i32.add i32.const 2
i32.load) i32.sub)
(func (;3;) (type 2) (param i32) (result i32) (func (;6;) (type 6) (param i32)
local.get 0 local.get 0
memory.grow) call 0)
(memory (;0;) 1 2) (export "one" (func 3))
(export "store" (func 1)) (export "two" (func 4))
(export "load" (func 2)) (export "three" (func 5))
(export "memory.grow" (func 3))) (export "four" (func 6)))
"#;
static WAT2: &'static str = r#"
(module
(type $t0 (func (param i32)))
(type $t1 (func))
(func $print_i32 (export "print_i32") (type $t0) (param $lhs i32))
(func $print (export "print") (type $t1))
(table $table (export "table") 10 20 anyfunc)
(memory $memory (export "memory") 1 2)
(global $global_i32 (export "global_i32") i32 (i32.const 666)))
"#; "#;
fn get_wasm() -> Vec<u8> { fn get_wasm() -> Vec<u8> {
wat2wasm(WAT).unwrap() wat2wasm(WAT).unwrap()
} }
fn foobar(ctx: &mut Ctx) -> i32 {
42
}
fn main() -> Result<(), error::Error> { fn main() -> Result<(), error::Error> {
let wasm = get_wasm(); let wasm = get_wasm();
let module = compile(&wasm)?; let module = compile(&wasm)?;
let imports = imports! {}; let import_module = compile(&wat2wasm(WAT2).unwrap())?;
let import_instance = import_module.instantiate(&imports! {})?;
let imports = imports! {
"spectest" => import_instance,
};
println!("instantiating"); println!("instantiating");
let instance = module.instantiate(&imports)?; let instance = module.instantiate(&imports)?;
let foo = instance.dyn_func("store")?; let foo = instance.dyn_func("four")?;
let result = foo.call(&[Value::I32(0), Value::I32(1)]); let result = foo.call(&[Value::I32(10)]);
println!("result: {:?}", result); println!("result: {:?}", result);