From 8a7e03978bedc4403ef4f35fdf4c63a9fb5b862f Mon Sep 17 00:00:00 2001 From: kyren Date: Sat, 2 Dec 2017 15:41:53 -0500 Subject: [PATCH] Experimental protected versions of all used 'm' erroring functions --- src/ffi.rs | 3 +- src/lib.rs | 5 +- src/protected.rs | 258 +++++++++++++++++++++++++++++++++++++++++++++++ src/table.rs | 1 + src/util.rs | 105 ------------------- 5 files changed, 263 insertions(+), 109 deletions(-) create mode 100644 src/protected.rs diff --git a/src/ffi.rs b/src/ffi.rs index 05ab3fa..9b03b58 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,7 +1,6 @@ -//! Bindings to the Lua 5.3 C API. - #![allow(non_camel_case_types)] #![allow(non_snake_case)] +#![allow(unused)] use std::ptr; use std::os::raw::{c_char, c_double, c_int, c_longlong, c_void}; diff --git a/src/lib.rs b/src/lib.rs index 12542ad..b704fee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,10 +42,11 @@ extern crate libc; -pub mod ffi; +mod ffi; +mod error; #[macro_use] mod util; -mod error; +mod protected; mod types; mod lua; mod conversion; diff --git a/src/protected.rs b/src/protected.rs new file mode 100644 index 0000000..d6d9065 --- /dev/null +++ b/src/protected.rs @@ -0,0 +1,258 @@ +use std::os::raw::{c_int, c_void, c_char}; +use std::{mem, ptr}; + +use ffi; +use error::{Result}; +use util::{handle_error, pcall_with_traceback}; + +// Protected version of lua_gettable, uses 3 stack spaces, does not call checkstack. +pub unsafe fn pgettable(state: *mut ffi::lua_State, index: c_int) -> Result { + unsafe extern "C" fn gettable(state: *mut ffi::lua_State) -> c_int { + ffi::lua_gettable(state, -2); + 1 + } + + let table_index = ffi::lua_absindex(state, index); + + ffi::lua_pushcfunction(state, gettable); + ffi::lua_pushvalue(state, table_index); + ffi::lua_pushvalue(state, -3); + ffi::lua_remove(state, -4); + + handle_error(state, pcall_with_traceback(state, 2, 1))?; + Ok(ffi::lua_type(state, -1)) +} + +// Protected version of lua_settable, uses 4 stack spaces, does not call checkstack. +pub unsafe fn psettable(state: *mut ffi::lua_State, index: c_int) -> Result<()> { + unsafe extern "C" fn settable(state: *mut ffi::lua_State) -> c_int { + ffi::lua_settable(state, -3); + 0 + } + + let table_index = ffi::lua_absindex(state, index); + + ffi::lua_pushcfunction(state, settable); + ffi::lua_pushvalue(state, table_index); + ffi::lua_pushvalue(state, -4); + ffi::lua_pushvalue(state, -4); + ffi::lua_remove(state, -5); + ffi::lua_remove(state, -5); + + handle_error(state, pcall_with_traceback(state, 3, 0))?; + Ok(()) +} + +// Protected version of luaL_len, uses 2 stack spaces, does not call checkstack. +pub unsafe fn plen(state: *mut ffi::lua_State, index: c_int) -> Result { + unsafe extern "C" fn len(state: *mut ffi::lua_State) -> c_int { + ffi::lua_pushinteger(state, ffi::luaL_len(state, -1)); + 1 + } + + let table_index = ffi::lua_absindex(state, index); + + ffi::lua_pushcfunction(state, len); + ffi::lua_pushvalue(state, table_index); + + handle_error(state, pcall_with_traceback(state, 1, 1))?; + let len = ffi::lua_tointeger(state, -1); + ffi::lua_pop(state, 1); + Ok(len) +} + +// Protected version of lua_geti, uses 3 stack spaces, does not call checkstack. +pub unsafe fn pgeti( + state: *mut ffi::lua_State, + index: c_int, + i: ffi::lua_Integer, +) -> Result { + unsafe extern "C" fn geti(state: *mut ffi::lua_State) -> c_int { + let i = ffi::lua_tointeger(state, -1); + ffi::lua_geti(state, -2, i); + 1 + } + + let table_index = ffi::lua_absindex(state, index); + + ffi::lua_pushcfunction(state, geti); + ffi::lua_pushvalue(state, table_index); + ffi::lua_pushinteger(state, i); + + handle_error(state, pcall_with_traceback(state, 2, 1))?; + Ok(ffi::lua_type(state, -1)) +} + +// Protected version of lua_next, uses 3 stack spaces, does not call checkstack. +pub unsafe fn pnext(state: *mut ffi::lua_State, index: c_int) -> Result { + unsafe extern "C" fn next(state: *mut ffi::lua_State) -> c_int { + if ffi::lua_next(state, -2) == 0 { + 0 + } else { + 2 + } + } + + let table_index = ffi::lua_absindex(state, index); + + ffi::lua_pushcfunction(state, next); + ffi::lua_pushvalue(state, table_index); + ffi::lua_pushvalue(state, -3); + ffi::lua_remove(state, -4); + + let stack_start = ffi::lua_gettop(state) - 3; + handle_error(state, pcall_with_traceback(state, 2, ffi::LUA_MULTRET))?; + let nresults = ffi::lua_gettop(state) - stack_start; + if nresults == 0 { + Ok(0) + } else { + Ok(1) + } +} + +// Protected version of lua_newtable, uses 1 stack space, does not call checkstack. +pub unsafe fn pnewtable(state: *mut ffi::lua_State) -> Result<()> { + unsafe extern "C" fn newtable(state: *mut ffi::lua_State) -> c_int { + ffi::lua_newtable(state); + 1 + } + + ffi::lua_pushcfunction(state, newtable); + + handle_error(state, pcall_with_traceback(state, 0, 1))?; + Ok(()) +} + +// Protected version of lua_newthread, uses 1 stack space, does not call checkstack. +pub unsafe fn pnewthread(state: *mut ffi::lua_State) -> Result<*mut ffi::lua_State> { + unsafe extern "C" fn newthread(state: *mut ffi::lua_State) -> c_int { + ffi::lua_newthread(state); + 1 + } + + ffi::lua_pushcfunction(state, newthread); + + handle_error(state, pcall_with_traceback(state, 0, 1))?; + Ok(ffi::lua_tothread(state, -1)) +} + +// Protected version of lua_newuserdata, uses 2 stack space, does not call checkstack. +pub unsafe fn pnewuserdata(state: *mut ffi::lua_State, size: usize) -> Result<*mut c_void> { + unsafe extern "C" fn newuserdata(state: *mut ffi::lua_State) -> c_int { + let size = ffi::lua_touserdata(state, -1) as usize; + ffi::lua_newuserdata(state, size); + 1 + } + + ffi::lua_pushcfunction(state, newuserdata); + ffi::lua_pushlightuserdata(state, size as *mut c_void); + + handle_error(state, pcall_with_traceback(state, 1, 1))?; + Ok(ffi::lua_touserdata(state, -1)) +} + +pub unsafe fn ppushcclosure(state: *mut ffi::lua_State, function: ffi::lua_CFunction, n: c_int) -> Result<()> { + unsafe extern "C" fn pushcclosure(state: *mut ffi::lua_State) -> c_int { + let function: ffi::lua_CFunction = mem::transmute(ffi::lua_touserdata(state, -2)); + let n = ffi::lua_touserdata(state, -1) as c_int; + ffi::lua_pop(state, 2); + ffi::lua_pushcclosure(state, function, n); + 1 + } + + if n == 0 { + ffi::lua_pushcclosure(state, function, 0); + } else { + ffi::lua_pushlightuserdata(state, function as *mut c_void); + ffi::lua_pushlightuserdata(state, n as *mut c_void); + + handle_error(state, pcall_with_traceback(state, n.checked_add(2).unwrap(), 1))?; + } + + Ok(()) +} + +pub unsafe fn ppushlstring(state: *mut ffi::lua_State, s: *const c_char, len: usize) -> Result<*const c_char> { + unsafe extern "C" fn pushlstring(state: *mut ffi::lua_State) -> c_int { + let s = ffi::lua_touserdata(state, -2) as *const c_char; + let len = ffi::lua_touserdata(state, -1) as usize; + ffi::lua_pushlstring(state, s, len); + 1 + } + + ffi::lua_pushlightuserdata(state, s as *mut c_void); + ffi::lua_pushlightuserdata(state, len as *mut c_void); + + handle_error(state, pcall_with_traceback(state, 2, 1))?; + + // If the value is already a string, I believe that lua_tostring / lua_tolstring never throw + // memory errors + Ok(ffi::lua_tostring(state, -1)) +} + +pub unsafe fn prawset(state: *mut ffi::lua_State, index: c_int) -> Result<()> { + unsafe extern "C" fn rawset(state: *mut ffi::lua_State) -> c_int { + ffi::lua_rawset(state, -3); + 0 + } + + let table_index = ffi::lua_absindex(state, index); + + ffi::lua_pushcfunction(state, rawset); + ffi::lua_pushvalue(state, table_index); + ffi::lua_pushvalue(state, -4); + ffi::lua_pushvalue(state, -4); + ffi::lua_remove(state, -5); + ffi::lua_remove(state, -5); + + handle_error(state, pcall_with_traceback(state, 3, 0))?; + Ok(()) +} + +pub unsafe fn ptolstring(state: *mut ffi::lua_State, index: c_int, len: *mut usize) -> Result<*const c_char> { + unsafe extern "C" fn tolstring(state: *mut ffi::lua_State) -> c_int { + let len = ffi::lua_touserdata(state, -2) as *mut usize; + ffi::lua_tolstring(state, -1, len); + 1 + } + + let index = ffi::lua_absindex(state, index); + + ffi::lua_pushcfunction(state, tolstring); + ffi::lua_pushlightuserdata(state, len as *mut c_void); + ffi::lua_pushvalue(state, index); + + match handle_error(state, pcall_with_traceback(state, 2, 1)) { + Ok(_) => { + ffi::lua_replace(state, index); + Ok(ffi::lua_tostring(state, index)) + } + Err(err) => { + ffi::lua_pop(state, 1); + Err(err) + } + } +} + +pub unsafe fn ptostring(state: *mut ffi::lua_State, index: c_int) -> Result<*const c_char> { + unsafe extern "C" fn tostring(state: *mut ffi::lua_State) -> c_int { + ffi::lua_tolstring(state, -1, ptr::null_mut()); + 1 + } + + let index = ffi::lua_absindex(state, index); + + ffi::lua_pushcfunction(state, tostring); + ffi::lua_pushvalue(state, index); + + match handle_error(state, pcall_with_traceback(state, 1, 1)) { + Ok(_) => { + ffi::lua_replace(state, index); + Ok(ffi::lua_tostring(state, index)) + } + Err(err) => { + ffi::lua_pop(state, 1); + Err(err) + } + } +} diff --git a/src/table.rs b/src/table.rs index 6642171..a00dbc1 100644 --- a/src/table.rs +++ b/src/table.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use ffi; use error::Result; use util::*; +use protected::*; use types::{Integer, LuaRef}; use lua::{FromLua, ToLua}; diff --git a/src/util.rs b/src/util.rs index 41c76fc..769024c 100644 --- a/src/util.rs +++ b/src/util.rs @@ -147,111 +147,6 @@ where res } -// Protected version of lua_gettable, uses 3 stack spaces, does not call checkstack. -pub unsafe fn pgettable(state: *mut ffi::lua_State, index: c_int) -> Result { - unsafe extern "C" fn gettable(state: *mut ffi::lua_State) -> c_int { - ffi::lua_gettable(state, -2); - 1 - } - - let table_index = ffi::lua_absindex(state, index); - - ffi::lua_pushcfunction(state, gettable); - ffi::lua_pushvalue(state, table_index); - ffi::lua_pushvalue(state, -3); - ffi::lua_remove(state, -4); - - handle_error(state, pcall_with_traceback(state, 2, 1))?; - Ok(ffi::lua_type(state, -1)) -} - -// Protected version of lua_settable, uses 4 stack spaces, does not call checkstack. -pub unsafe fn psettable(state: *mut ffi::lua_State, index: c_int) -> Result<()> { - unsafe extern "C" fn settable(state: *mut ffi::lua_State) -> c_int { - ffi::lua_settable(state, -3); - 0 - } - - let table_index = ffi::lua_absindex(state, index); - - ffi::lua_pushcfunction(state, settable); - ffi::lua_pushvalue(state, table_index); - ffi::lua_pushvalue(state, -4); - ffi::lua_pushvalue(state, -4); - ffi::lua_remove(state, -5); - ffi::lua_remove(state, -5); - - handle_error(state, pcall_with_traceback(state, 3, 0))?; - Ok(()) -} - -// Protected version of luaL_len, uses 2 stack spaces, does not call checkstack. -pub unsafe fn plen(state: *mut ffi::lua_State, index: c_int) -> Result { - unsafe extern "C" fn len(state: *mut ffi::lua_State) -> c_int { - ffi::lua_pushinteger(state, ffi::luaL_len(state, -1)); - 1 - } - - let table_index = ffi::lua_absindex(state, index); - - ffi::lua_pushcfunction(state, len); - ffi::lua_pushvalue(state, table_index); - - handle_error(state, pcall_with_traceback(state, 1, 1))?; - let len = ffi::lua_tointeger(state, -1); - ffi::lua_pop(state, 1); - Ok(len) -} - -// Protected version of lua_geti, uses 3 stack spaces, does not call checkstack. -pub unsafe fn pgeti( - state: *mut ffi::lua_State, - index: c_int, - i: ffi::lua_Integer, -) -> Result { - unsafe extern "C" fn geti(state: *mut ffi::lua_State) -> c_int { - let i = ffi::lua_tointeger(state, -1); - ffi::lua_geti(state, -2, i); - 1 - } - - let table_index = ffi::lua_absindex(state, index); - - ffi::lua_pushcfunction(state, geti); - ffi::lua_pushvalue(state, table_index); - ffi::lua_pushinteger(state, i); - - handle_error(state, pcall_with_traceback(state, 2, 1))?; - Ok(ffi::lua_type(state, -1)) -} - -// Protected version of lua_next, uses 3 stack spaces, does not call checkstack. -pub unsafe fn pnext(state: *mut ffi::lua_State, index: c_int) -> Result { - unsafe extern "C" fn next(state: *mut ffi::lua_State) -> c_int { - if ffi::lua_next(state, -2) == 0 { - 0 - } else { - 2 - } - } - - let table_index = ffi::lua_absindex(state, index); - - ffi::lua_pushcfunction(state, next); - ffi::lua_pushvalue(state, table_index); - ffi::lua_pushvalue(state, -3); - ffi::lua_remove(state, -4); - - let stack_start = ffi::lua_gettop(state) - 3; - handle_error(state, pcall_with_traceback(state, 2, ffi::LUA_MULTRET))?; - let nresults = ffi::lua_gettop(state) - stack_start; - if nresults == 0 { - Ok(0) - } else { - Ok(1) - } -} - // If the return code indicates an error, pops the error off of the stack and // returns Err. 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