Always ensure LUA_MINSTACK available stack spaces on callback

Otherwise, cleanly error with an appropriate stack error.  Part of an effort to
ensure that it should not be possible to trigger a stack space assert.
This commit is contained in:
kyren 2018-03-19 14:36:01 -04:00
parent 4b6809c766
commit 0d5e45e800
2 changed files with 15 additions and 10 deletions

View File

@ -53,6 +53,7 @@ pub const LUA_REGISTRYINDEX: c_int = -LUAI_MAXSTACK - 1000;
pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1; pub const LUA_RIDX_MAINTHREAD: lua_Integer = 1;
pub const LUA_RIDX_GLOBALS: lua_Integer = 2; pub const LUA_RIDX_GLOBALS: lua_Integer = 2;
pub const LUA_IDSIZE: c_int = 60; pub const LUA_IDSIZE: c_int = 60;
pub const LUA_MINSTACK: c_int = 20;
// Not actually defined in lua.h / luaconf.h // Not actually defined in lua.h / luaconf.h
pub const LUA_MAX_UPVALUES: c_int = 255; pub const LUA_MAX_UPVALUES: c_int = 255;

View File

@ -1013,15 +1013,13 @@ impl Lua {
ref_stack_slots: Default::default(), ref_stack_slots: Default::default(),
}; };
let args = lua.setup_callback_stack_slots(); let args = lua.setup_callback_stack()?;
let func = get_userdata::<Callback>(state, ffi::lua_upvalueindex(1)); let func = get_userdata::<Callback>(state, ffi::lua_upvalueindex(1));
let results = (*func)(&lua, args)?; let results = (*func)(&lua, args)?;
let nresults = results.len() as c_int; let nresults = results.len() as c_int;
check_stack_err(state, nresults)?; check_stack_err(state, nresults)?;
for r in results { for r in results {
lua.push_value(r); lua.push_value(r);
} }
@ -1175,8 +1173,9 @@ impl Lua {
} }
// Set up the stack slot area in a callback, returning all arguments on the stack as a // Set up the stack slot area in a callback, returning all arguments on the stack as a
// MultiValue // MultiValue. Also ensures that at least LUA_MINSTACK extra stack slots are available for use
fn setup_callback_stack_slots<'lua>(&'lua self) -> MultiValue<'lua> { // in the callback.
fn setup_callback_stack<'lua>(&'lua self) -> Result<MultiValue<'lua>> {
unsafe { unsafe {
check_stack(self.state, 2); check_stack(self.state, 2);
@ -1243,15 +1242,19 @@ impl Lua {
args.push_front(Value::Thread(Thread(make_ref()))); args.push_front(Value::Thread(Thread(make_ref())));
} }
_ => rlua_panic!("LUA_TNONE in setup_callback_stack_slots"), _ => rlua_panic!("LUA_TNONE in setup_callback_stack"),
} }
} }
if nargs < REF_STACK_SIZE { if nargs < REF_STACK_SIZE {
check_stack(self.state, REF_STACK_SIZE - nargs); check_stack_err(self.state, REF_STACK_SIZE - nargs + ffi::LUA_MINSTACK)?;
ffi::lua_settop(self.state, REF_STACK_SIZE); ffi::lua_settop(self.state, REF_STACK_SIZE);
args Ok(args)
} else if nargs > REF_STACK_SIZE { } else if nargs > REF_STACK_SIZE {
if nargs - REF_STACK_SIZE < ffi::LUA_MINSTACK {
check_stack_err(self.state, ffi::LUA_MINSTACK - (nargs - REF_STACK_SIZE))?;
}
// If the total number of arguments exceeds the ref stack area, pop off the rest of // If the total number of arguments exceeds the ref stack area, pop off the rest of
// the arguments as normal. // the arguments as normal.
let mut extra_args = Vec::new(); let mut extra_args = Vec::new();
@ -1260,9 +1263,10 @@ impl Lua {
extra_args.push(self.pop_value()); extra_args.push(self.pop_value());
} }
extra_args.extend(args.into_vec_rev()); extra_args.extend(args.into_vec_rev());
MultiValue::from_vec_rev(extra_args) Ok(MultiValue::from_vec_rev(extra_args))
} else { } else {
args check_stack_err(self.state, ffi::LUA_MINSTACK)?;
Ok(args)
} }
} }
} }