Skip to content

Commit eb154e4

Browse files
committed
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.
1 parent 37feaeb commit eb154e4

File tree

1 file changed

+16
-13
lines changed

1 file changed

+16
-13
lines changed

src/util.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -112,23 +112,23 @@ pub unsafe fn protect_lua_call<F, R>(
112112
f: F,
113113
) -> Result<R>
114114
where
115-
F: FnOnce(*mut ffi::lua_State) -> R,
115+
F: Fn(*mut ffi::lua_State) -> R,
116+
R: Copy,
116117
{
117118
struct Params<F, R> {
118-
function: Option<F>,
119-
result: Option<R>,
119+
function: *const F,
120+
result: R,
120121
nresults: c_int,
121122
}
122123

123124
unsafe extern "C" fn do_call<F, R>(state: *mut ffi::lua_State) -> c_int
124125
where
125-
F: FnOnce(*mut ffi::lua_State) -> R,
126+
F: Fn(*mut ffi::lua_State) -> R,
126127
{
127128
let params = ffi::lua_touserdata(state, -1) as *mut Params<F, R>;
128129
ffi::lua_pop(state, 1);
129130

130-
let function = (*params).function.take().unwrap();
131-
(*params).result = Some(function(state));
131+
(*params).result = (*(*params).function)(state);
132132

133133
if (*params).nresults == ffi::LUA_MULTRET {
134134
ffi::lua_gettop(state)
@@ -144,8 +144,8 @@ where
144144
ffi::lua_rotate(state, stack_start + 1, 2);
145145

146146
let mut params = Params {
147-
function: Some(f),
148-
result: None,
147+
function: &f,
148+
result: mem::uninitialized(),
149149
nresults,
150150
};
151151

@@ -154,7 +154,9 @@ where
154154
ffi::lua_remove(state, stack_start + 1);
155155

156156
if ret == ffi::LUA_OK {
157-
Ok(params.result.take().unwrap())
157+
// LUA_OK is only returned when the do_call function has completed successfully, so
158+
// params.result is definitely initialized.
159+
Ok(params.result)
158160
} else {
159161
Err(pop_error(state, ret))
160162
}
@@ -228,10 +230,11 @@ pub unsafe fn push_string(state: *mut ffi::lua_State, s: &str) -> Result<()> {
228230

229231
// Internally uses 4 stack spaces, does not call checkstack
230232
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
231-
protect_lua_call(state, 0, 1, move |state| {
232-
let ud = ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T;
233-
ptr::write(ud, t);
234-
})
233+
let ud = protect_lua_call(state, 0, 1, move |state| {
234+
ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T
235+
})?;
236+
ptr::write(ud, t);
237+
Ok(())
235238
}
236239

237240
pub unsafe fn get_userdata<T>(state: *mut ffi::lua_State, index: c_int) -> *mut T {

0 commit comments

Comments
 (0)