diff --git a/Cargo.toml b/Cargo.toml index 3d93404..3f07e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,5 +32,4 @@ compiletest_rs = { version = "0.3", optional = true } gcc = { version = "0.3.52", optional = true } [dev-dependencies] -rustyline = "1.0.0" - +rustyline = "1.0.0" \ No newline at end of file diff --git a/src/function.rs b/src/function.rs index c268de3..97906a3 100644 --- a/src/function.rs +++ b/src/function.rs @@ -80,7 +80,7 @@ impl<'lua> Function<'lua> { } let nresults = ffi::lua_gettop(lua.state) - stack_start; let mut results = MultiValue::new(); - check_stack(lua.state, 1); + check_stack(lua.state, 2); for _ in 0..nresults { results.push_front(lua.pop_value(lua.state)); } diff --git a/src/lua.rs b/src/lua.rs index 65d03d9..f0722f9 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -565,7 +565,7 @@ impl Lua { } stack_err_guard(self.state, 0, || { - check_stack(self.state, 1); + check_stack(self.state, 2); ffi::lua_rawgeti( self.state, ffi::LUA_REGISTRYINDEX, @@ -672,7 +672,7 @@ impl Lua { } } - // Uses 1 stack space, does not call checkstack + // Uses 2 stack spaces, does not call checkstack pub(crate) unsafe fn pop_value(&self, state: *mut ffi::lua_State) -> Value { match ffi::lua_type(state, -1) { ffi::LUA_TNIL => { @@ -709,10 +709,9 @@ impl Lua { ffi::LUA_TFUNCTION => Value::Function(Function(self.pop_ref(state))), ffi::LUA_TUSERDATA => { - // It should not be possible to interact with userdata types - // other than custom UserData types OR a WrappedError. - // WrappedPanic should never be able to be caught in lua, so it - // should never be here. + // It should not be possible to interact with userdata types other than custom + // UserData types OR a WrappedError. WrappedPanic should never be able to be caught + // in lua, so it should never be here. if let Some(err) = pop_wrapped_error(state) { Value::Error(err) } else { @@ -1011,7 +1010,7 @@ impl Lua { let nargs = ffi::lua_gettop(state); let mut args = MultiValue::new(); - check_stack(state, 1); + check_stack(state, 2); for _ in 0..nargs { args.push_front(lua.pop_value(state)); } diff --git a/src/string.rs b/src/string.rs index 5eda24a..31e937b 100644 --- a/src/string.rs +++ b/src/string.rs @@ -72,7 +72,11 @@ impl<'lua> String<'lua> { stack_guard(lua.state, 0, || { check_stack(lua.state, 1); lua.push_ref(lua.state, &self.0); - assert_eq!(ffi::lua_type(lua.state, -1), ffi::LUA_TSTRING); + lua_internal_assert!( + lua.state, + ffi::lua_type(lua.state, -1) == ffi::LUA_TSTRING, + "string ref is not string type" + ); let mut size = 0; // This will not trigger a 'm' error, because the reference is guaranteed to be of diff --git a/src/table.rs b/src/table.rs index afac271..adf156d 100644 --- a/src/table.rs +++ b/src/table.rs @@ -347,7 +347,7 @@ where unsafe { stack_guard(lua.state, 0, || { - check_stack(lua.state, 5); + check_stack(lua.state, 6); lua.push_ref(lua.state, &self.table); lua.push_ref(lua.state, &next_key); @@ -409,7 +409,7 @@ where unsafe { stack_guard(lua.state, 0, || { - check_stack(lua.state, 4); + check_stack(lua.state, 5); lua.push_ref(lua.state, &self.table); match protect_lua_call(lua.state, 1, 1, |state| ffi::lua_geti(state, -1, index)) diff --git a/src/thread.rs b/src/thread.rs index d775827..ab5b97a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -107,7 +107,7 @@ impl<'lua> Thread<'lua> { let nresults = ffi::lua_gettop(thread_state); let mut results = MultiValue::new(); - check_stack(thread_state, 1); + check_stack(thread_state, 2); for _ in 0..nresults { results.push_front(lua.pop_value(thread_state)); } diff --git a/src/userdata.rs b/src/userdata.rs index 7929de5..e29aa59 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -470,7 +470,7 @@ impl<'lua> AnyUserData<'lua> { let lua = self.0.lua; unsafe { stack_err_guard(lua.state, 0, || { - check_stack(lua.state, 2); + check_stack(lua.state, 3); lua.push_ref(lua.state, &self.0); ffi::lua_getuservalue(lua.state, -1); let res = V::from_lua(lua.pop_value(lua.state), lua)?; diff --git a/src/util.rs b/src/util.rs index a56f132..660c058 100644 --- a/src/util.rs +++ b/src/util.rs @@ -179,6 +179,7 @@ where // Pops an error off of the stack and returns it. If the error is actually a WrappedPanic, clears // the current lua stack and continues the panic. If the error on the top of the stack is actually // a WrappedError, just returns it. Otherwise, interprets the error as the appropriate lua error. +// Uses 2 stack spaces, does not call lua_checkstack. pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error { lua_internal_assert!( state, @@ -334,6 +335,8 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int { // A variant of pcall that does not allow lua to catch panic errors from callback_error pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int { + ffi::luaL_checkstack(state, 2, ptr::null()); + let top = ffi::lua_gettop(state); if top == 0 { ffi::lua_pushstring(state, cstr!("not enough arguments to pcall")); @@ -355,6 +358,8 @@ pub unsafe extern "C" fn safe_pcall(state: *mut ffi::lua_State) -> c_int { // A variant of xpcall that does not allow lua to catch panic errors from callback_error pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int { unsafe extern "C" fn xpcall_msgh(state: *mut ffi::lua_State) -> c_int { + ffi::luaL_checkstack(state, 2, ptr::null()); + if is_wrapped_panic(state, -1) { 1 } else { @@ -365,6 +370,8 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int { } } + ffi::luaL_checkstack(state, 2, ptr::null()); + let top = ffi::lua_gettop(state); if top < 2 { ffi::lua_pushstring(state, cstr!("not enough arguments to xpcall")); @@ -411,10 +418,11 @@ pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) { ffi::lua_setmetatable(state, -2); } -// Pops a WrappedError off of the top of the stack, if it is a WrappedError. If -// it is not a WrappedError, returns None and does not pop anything. +// Pops a WrappedError off of the top of the stack, if it is a WrappedError. If it is not a +// WrappedError, returns None and does not pop anything. Uses 2 stack spaces and does not call +// lua_checkstack pub unsafe fn pop_wrapped_error(state: *mut ffi::lua_State) -> Option { - if ffi::lua_gettop(state) == 0 || !is_wrapped_error(state, -1) { + if !is_wrapped_error(state, -1) { None } else { let err = &*get_userdata::(state, -1); @@ -456,16 +464,9 @@ unsafe fn push_wrapped_panic(state: *mut ffi::lua_State, panic: Box) ffi::lua_setmetatable(state, -2); } -// Checks if the value at the given index is a WrappedError +// Checks if the value at the given index is a WrappedError, uses 2 stack spaces and does not call +// lua_checkstack. unsafe fn is_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> bool { - assert_ne!( - ffi::lua_checkstack(state, 2), - 0, - "somehow not enough stack space to check if a value is a WrappedError" - ); - - let index = ffi::lua_absindex(state, index); - let userdata = ffi::lua_touserdata(state, index); if userdata.is_null() { return false; @@ -481,16 +482,9 @@ unsafe fn is_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> bool { res } -// Checks if the value at the given index is a WrappedPanic +// Checks if the value at the given index is a WrappedPanic. Uses 2 stack spaces and does not call +// lua_checkstack. unsafe fn is_wrapped_panic(state: *mut ffi::lua_State, index: c_int) -> bool { - assert_ne!( - ffi::lua_checkstack(state, 2), - 0, - "somehow not enough stack space to check if a value is a wrapped panic" - ); - - let index = ffi::lua_absindex(state, index); - let userdata = ffi::lua_touserdata(state, index); if userdata.is_null() { return false; @@ -510,6 +504,8 @@ unsafe fn get_error_metatable(state: *mut ffi::lua_State) -> c_int { static ERROR_METATABLE_REGISTRY_KEY: u8 = 0; unsafe extern "C" fn error_tostring(state: *mut ffi::lua_State) -> c_int { + ffi::luaL_checkstack(state, 2, ptr::null()); + callback_error(state, || { if is_wrapped_error(state, -1) { let error = get_userdata::(state, -1);