From 0d5e45e80096b1e072e02869c6eff4fbe63824df Mon Sep 17 00:00:00 2001 From: kyren Date: Mon, 19 Mar 2018 14:36:01 -0400 Subject: [PATCH] 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. --- src/ffi.rs | 1 + src/lua.rs | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index d3dc2bb..f72045c 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -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_GLOBALS: lua_Integer = 2; pub const LUA_IDSIZE: c_int = 60; +pub const LUA_MINSTACK: c_int = 20; // Not actually defined in lua.h / luaconf.h pub const LUA_MAX_UPVALUES: c_int = 255; diff --git a/src/lua.rs b/src/lua.rs index 1e7f959..9dddd4b 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1013,15 +1013,13 @@ impl Lua { ref_stack_slots: Default::default(), }; - let args = lua.setup_callback_stack_slots(); - + let args = lua.setup_callback_stack()?; let func = get_userdata::(state, ffi::lua_upvalueindex(1)); let results = (*func)(&lua, args)?; let nresults = results.len() as c_int; check_stack_err(state, nresults)?; - for r in results { 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 - // MultiValue - fn setup_callback_stack_slots<'lua>(&'lua self) -> MultiValue<'lua> { + // MultiValue. Also ensures that at least LUA_MINSTACK extra stack slots are available for use + // in the callback. + fn setup_callback_stack<'lua>(&'lua self) -> Result> { unsafe { check_stack(self.state, 2); @@ -1243,15 +1242,19 @@ impl Lua { 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 { - 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); - args + Ok(args) } 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 // the arguments as normal. let mut extra_args = Vec::new(); @@ -1260,9 +1263,10 @@ impl Lua { extra_args.push(self.pop_value()); } extra_args.extend(args.into_vec_rev()); - MultiValue::from_vec_rev(extra_args) + Ok(MultiValue::from_vec_rev(extra_args)) } else { - args + check_stack_err(self.state, ffi::LUA_MINSTACK)?; + Ok(args) } } }