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:
kyren 2018-03-06 06:22:05 -05:00
parent 37feaebdce
commit eb154e4a9e
1 changed files with 16 additions and 13 deletions

View File

@ -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 {