From d415455ccb9789753d76f5e37a92d0dce2bca0bf Mon Sep 17 00:00:00 2001 From: kyren Date: Thu, 27 Jul 2017 17:16:40 -0400 Subject: [PATCH] Fix several bugs with error handling in xxx_with_traceback functions In resume_with_traceback, always use the coroutine stack for error handling so we don't miss panics, in both _with_traceback functions remove the temporary traceback entry from the stack. --- src/lua.rs | 2 +- src/tests.rs | 14 ++++++++++++++ src/util.rs | 14 +++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/lua.rs b/src/lua.rs index 95d695b..3c98376 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -858,7 +858,7 @@ impl<'lua> Thread<'lua> { } handle_error( - lua.state, + thread_state, resume_with_traceback(thread_state, lua.state, nargs), )?; diff --git a/src/tests.rs b/src/tests.rs index b5a7ca0..bf64b6b 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -893,3 +893,17 @@ fn coroutine_from_closure() { let thrd: Thread = lua.eval("coroutine.create(main)", None).unwrap(); thrd.resume::<_, ()>(()).unwrap(); } + +#[test] +#[should_panic] +fn coroutine_panic() { + let lua = Lua::new(); + let thrd_main = lua.create_function(|lua, _| { + // whoops, 'main' has a wrong type + let _coro: u32 = lua.globals().get("main").unwrap(); + lua.pack(()) + }); + lua.globals().set("main", thrd_main.clone()).unwrap(); + let thrd: Thread = lua.create_thread(thrd_main); + thrd.resume::<_, ()>(()).unwrap(); +} diff --git a/src/util.rs b/src/util.rs index 7808fd2..2cc56ed 100644 --- a/src/util.rs +++ b/src/util.rs @@ -381,6 +381,7 @@ pub unsafe fn pcall_with_traceback( .unwrap_or_else(|_| "") .to_owned(); push_wrapped_error(state, Error::CallbackError(traceback, Arc::new(error))); + ffi::lua_remove(state, -2); } else if !is_wrapped_panic(state, 1) { let s = ffi::lua_tolstring(state, 1, ptr::null_mut()); if !s.is_null() { @@ -388,6 +389,7 @@ pub unsafe fn pcall_with_traceback( } else { ffi::luaL_traceback(state, state, cstr!(""), 0); } + ffi::lua_remove(state, -2); } 1 } @@ -408,19 +410,21 @@ pub unsafe fn resume_with_traceback( let res = ffi::lua_resume(state, from, nargs); if res != ffi::LUA_OK && res != ffi::LUA_YIELD { if let Some(error) = pop_wrapped_error(state) { - ffi::luaL_traceback(from, state, ptr::null(), 0); - let traceback = CStr::from_ptr(ffi::lua_tolstring(from, -1, ptr::null_mut())) + ffi::luaL_traceback(state, state, ptr::null(), 0); + let traceback = CStr::from_ptr(ffi::lua_tolstring(state, -1, ptr::null_mut())) .to_str() .unwrap_or_else(|_| "") .to_owned(); - push_wrapped_error(from, Error::CallbackError(traceback, Arc::new(error))); + push_wrapped_error(state, Error::CallbackError(traceback, Arc::new(error))); + ffi::lua_remove(state, -2); } else if !is_wrapped_panic(state, 1) { let s = ffi::lua_tolstring(state, 1, ptr::null_mut()); if !s.is_null() { - ffi::luaL_traceback(from, state, s, 0); + ffi::luaL_traceback(state, state, s, 0); } else { - ffi::luaL_traceback(from, state, cstr!(""), 0); + ffi::luaL_traceback(state, state, cstr!(""), 0); } + ffi::lua_remove(state, -2); } } res