From f9f3d0580458e8af7051095eec16022a5fa1bbba Mon Sep 17 00:00:00 2001 From: kyren Date: Wed, 2 Aug 2017 10:42:18 -0400 Subject: [PATCH] Fix argument bugs with pcall / xpcall, add tests for it --- src/tests.rs | 29 +++++++++++++++++++++++++++++ src/util.rs | 14 ++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index 6e68716..af972f4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -889,6 +889,35 @@ fn coroutine_panic() { thrd.resume::<_, ()>(()).unwrap(); } +#[test] +fn test_pcall_xpcall() { + let lua = Lua::new(); + // make sure that we handle not enough arguments + assert!(lua.exec::<()>("pcall()", None).is_err()); + assert!(lua.exec::<()>("xpcall()", None).is_err()); + assert!(lua.exec::<()>("xpcall(function() end)", None).is_err()); + + lua.exec::<()>( + r#" + pcall_error = nil + _, pcall_error = pcall(error, "testerror") + + xpcall_error = nil + xpcall(error, function(err) xpcall_error = err end, "testerror") + "#, + None, + ).unwrap(); + + assert_eq!( + lua.globals().get::<_, String>("pcall_error").unwrap(), + "testerror" + ); + + assert_eq!( + lua.globals().get::<_, String>("xpcall_error").unwrap(), + "testerror" + ); +} // Need to use compiletest-rs or similar to make sure these don't compile. /* diff --git a/src/util.rs b/src/util.rs index 2cc56ed..1cd2a26 100644 --- a/src/util.rs +++ b/src/util.rs @@ -432,7 +432,11 @@ pub unsafe fn resume_with_traceback( // 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 { - if ffi::lua_pcall(state, ffi::lua_gettop(state) - 1, ffi::LUA_MULTRET, 0) != ffi::LUA_OK { + let top = ffi::lua_gettop(state); + if top == 0 { + push_string(state, "not enough arguments to pcall"); + ffi::lua_error(state); + } else if ffi::lua_pcall(state, top - 1, ffi::LUA_MULTRET, 0) != ffi::LUA_OK { if is_wrapped_panic(state, -1) { ffi::lua_error(state); } @@ -459,10 +463,16 @@ pub unsafe extern "C" fn safe_xpcall(state: *mut ffi::lua_State) -> c_int { } } + let top = ffi::lua_gettop(state); + if top < 2 { + push_string(state, "not enough arguments to xpcall"); + ffi::lua_error(state); + } + ffi::lua_pushvalue(state, 2); ffi::lua_pushcclosure(state, xpcall_msgh, 1); ffi::lua_copy(state, 1, 2); - ffi::lua_insert(state, 1); + ffi::lua_replace(state, 1); let res = ffi::lua_pcall(state, ffi::lua_gettop(state) - 2, ffi::LUA_MULTRET, 1); if res != ffi::LUA_OK {