Further safety updates of `protect_lua_call`
Only allow Copy result types and Fn parameter functions, do not risk dropping anything inside function passed to lua_pcall.
This commit is contained in:
parent
37feaebdce
commit
eb154e4a9e
27
src/util.rs
27
src/util.rs
|
@ -112,23 +112,23 @@ pub unsafe fn protect_lua_call<F, R>(
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<R>
|
) -> Result<R>
|
||||||
where
|
where
|
||||||
F: FnOnce(*mut ffi::lua_State) -> R,
|
F: Fn(*mut ffi::lua_State) -> R,
|
||||||
|
R: Copy,
|
||||||
{
|
{
|
||||||
struct Params<F, R> {
|
struct Params<F, R> {
|
||||||
function: Option<F>,
|
function: *const F,
|
||||||
result: Option<R>,
|
result: R,
|
||||||
nresults: c_int,
|
nresults: c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn do_call<F, R>(state: *mut ffi::lua_State) -> c_int
|
unsafe extern "C" fn do_call<F, R>(state: *mut ffi::lua_State) -> c_int
|
||||||
where
|
where
|
||||||
F: FnOnce(*mut ffi::lua_State) -> R,
|
F: Fn(*mut ffi::lua_State) -> R,
|
||||||
{
|
{
|
||||||
let params = ffi::lua_touserdata(state, -1) as *mut Params<F, R>;
|
let params = ffi::lua_touserdata(state, -1) as *mut Params<F, R>;
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
|
|
||||||
let function = (*params).function.take().unwrap();
|
(*params).result = (*(*params).function)(state);
|
||||||
(*params).result = Some(function(state));
|
|
||||||
|
|
||||||
if (*params).nresults == ffi::LUA_MULTRET {
|
if (*params).nresults == ffi::LUA_MULTRET {
|
||||||
ffi::lua_gettop(state)
|
ffi::lua_gettop(state)
|
||||||
|
@ -144,8 +144,8 @@ where
|
||||||
ffi::lua_rotate(state, stack_start + 1, 2);
|
ffi::lua_rotate(state, stack_start + 1, 2);
|
||||||
|
|
||||||
let mut params = Params {
|
let mut params = Params {
|
||||||
function: Some(f),
|
function: &f,
|
||||||
result: None,
|
result: mem::uninitialized(),
|
||||||
nresults,
|
nresults,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -154,7 +154,9 @@ where
|
||||||
ffi::lua_remove(state, stack_start + 1);
|
ffi::lua_remove(state, stack_start + 1);
|
||||||
|
|
||||||
if ret == ffi::LUA_OK {
|
if ret == ffi::LUA_OK {
|
||||||
Ok(params.result.take().unwrap())
|
// LUA_OK is only returned when the do_call function has completed successfully, so
|
||||||
|
// params.result is definitely initialized.
|
||||||
|
Ok(params.result)
|
||||||
} else {
|
} else {
|
||||||
Err(pop_error(state, ret))
|
Err(pop_error(state, ret))
|
||||||
}
|
}
|
||||||
|
@ -228,10 +230,11 @@ pub unsafe fn push_string(state: *mut ffi::lua_State, s: &str) -> Result<()> {
|
||||||
|
|
||||||
// Internally uses 4 stack spaces, does not call checkstack
|
// Internally uses 4 stack spaces, does not call checkstack
|
||||||
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||||
protect_lua_call(state, 0, 1, move |state| {
|
let ud = protect_lua_call(state, 0, 1, move |state| {
|
||||||
let ud = ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T;
|
ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T
|
||||||
|
})?;
|
||||||
ptr::write(ud, t);
|
ptr::write(ud, t);
|
||||||
})
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn get_userdata<T>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
pub unsafe fn get_userdata<T>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
||||||
|
|
Loading…
Reference in New Issue