mirror of
https://github.com/fluencelabs/wasmer
synced 2025-05-12 02:27:11 +00:00
fix(runtime-core) Remove undefined behavior with mem::transmute
.
In the `wrap` functions, we use `std::mem::transmute(&())` to get the pointer to the value “around” `wrap` (`Fn` has a method `to_raw` which declares a `wrap` function, which uses `transmute` to retrieve `Fn`). This is an undefined behavior. It was working until the `FuncCtx` is introduced. Since then, the undefined behavior was causing an error with the Singlepass backend. This patch stores the pointer to `Fn` in `func_env`, so that the pointer to the user-defined host function is always predictable.
This commit is contained in:
parent
a4ba429ed0
commit
c4c88f8af5
@ -517,18 +517,18 @@ macro_rules! impl_traits {
|
||||
let func_env = func_ctx.func_env;
|
||||
|
||||
let func: &FN = match func_env {
|
||||
// The imported function is a closure with a
|
||||
// captured environment.
|
||||
// The imported function is a regular
|
||||
// function, a closure without a captured
|
||||
// environmet, or a closure with a captured
|
||||
// environment.
|
||||
Some(func_env) => unsafe {
|
||||
let func: NonNull<FN> = func_env.cast();
|
||||
|
||||
&*func.as_ptr()
|
||||
},
|
||||
|
||||
// The imported function is a regular function
|
||||
// or a closure without a captured
|
||||
// environment.
|
||||
None => unsafe { mem::transmute_copy(&()) }
|
||||
// This branch is supposed to be unreachable.
|
||||
None => unreachable!()
|
||||
};
|
||||
|
||||
// Catch unwind in case of errors.
|
||||
@ -563,7 +563,7 @@ macro_rules! impl_traits {
|
||||
// `FN` is a function pointer, or a closure
|
||||
// _without_ a captured environment.
|
||||
if mem::size_of::<Self>() == 0 {
|
||||
None
|
||||
NonNull::new(&self as *const _ as *mut vm::FuncEnv)
|
||||
}
|
||||
// `FN` is a closure _with_ a captured
|
||||
// environment. Grab it.
|
||||
@ -613,18 +613,18 @@ macro_rules! impl_traits {
|
||||
let func_env = func_ctx.func_env;
|
||||
|
||||
let func: &FN = match func_env {
|
||||
// The imported function is a closure with a
|
||||
// captured environment.
|
||||
// The imported function is a regular
|
||||
// function, a closure without a captured
|
||||
// environmet, or a closure with a captured
|
||||
// environment.
|
||||
Some(func_env) => unsafe {
|
||||
let func: NonNull<FN> = func_env.cast();
|
||||
|
||||
&*func.as_ptr()
|
||||
},
|
||||
|
||||
// The imported function is a regular function
|
||||
// or a closure without a captured
|
||||
// environment.
|
||||
None => unsafe { mem::transmute_copy(&()) }
|
||||
// This branch is supposed to be unreachable.
|
||||
None => unreachable!()
|
||||
};
|
||||
|
||||
// Catch unwind in case of errors.
|
||||
@ -656,7 +656,7 @@ macro_rules! impl_traits {
|
||||
// `FN` is a function pointer, or a closure
|
||||
// _without_ a captured environment.
|
||||
if mem::size_of::<Self>() == 0 {
|
||||
None
|
||||
NonNull::new(&self as *const _ as *mut vm::FuncEnv)
|
||||
}
|
||||
// `FN` is a closure _with_ a captured
|
||||
// environment. Grab it.
|
||||
|
@ -514,12 +514,18 @@ pub struct FuncEnv {
|
||||
_private: [u8; 0],
|
||||
}
|
||||
|
||||
/// Represents a function context. It is used by imported function
|
||||
/// Represents a function context. It is used by imported functions
|
||||
/// only.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct FuncCtx {
|
||||
/// The `Ctx` pointer.
|
||||
pub(crate) vmctx: NonNull<Ctx>,
|
||||
|
||||
/// A pointer to the function environment. It is used by imported
|
||||
/// functions only to store the pointer to the real host function,
|
||||
/// whether it is a regular function, or a closure with or without
|
||||
/// a captured environment.
|
||||
pub(crate) func_env: Option<NonNull<FuncEnv>>,
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user