diff options
author | Alex Orlenko <zxteam@protonmail.com> | 2021-04-09 12:05:03 +0100 |
---|---|---|
committer | Alex Orlenko <zxteam@protonmail.com> | 2021-04-27 00:29:38 +0100 |
commit | ced808d5ab5777abf283a72f71c51ef8040b02f0 (patch) | |
tree | 52d97b5819f73f284886391943dee7e45e3b1b4b /src/userdata.rs | |
parent | c95ac32741d121652bd895730b2eb67fb5c2cef3 (diff) | |
download | mlua-ced808d5ab5777abf283a72f71c51ef8040b02f0.zip |
Don't trigger longjmp in rust.
Motivation behind this change is upcoming breaking change in Rust
compiler v1.52.0 to prevent unwinding across FFI boundaries.
https://github.com/rust-lang/rust/pull/76570
The new functionality requires nightly compiler to declare FFI
functions as "C-unwind".
The fundamental solution is to use C shim to wrap "e" and "m"
Lua functions in pcall.
Additionally define Rust calling convention to trigger lua_error
on Rust behalf.
Diffstat (limited to 'src/userdata.rs')
-rw-r--r-- | src/userdata.rs | 56 |
1 files changed, 27 insertions, 29 deletions
diff --git a/src/userdata.rs b/src/userdata.rs index 12b4518..f3d01c9 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -1,3 +1,4 @@ +// OK use std::cell::{Ref, RefMut}; use std::fmt; use std::hash::{Hash, Hasher}; @@ -17,7 +18,7 @@ use crate::ffi; use crate::function::Function; use crate::lua::Lua; use crate::table::{Table, TablePairs}; -use crate::types::{LuaRef, MaybeSend, UserDataCell}; +use crate::types::{Integer, LuaRef, MaybeSend, UserDataCell}; use crate::util::{assert_stack, get_destructed_userdata_metatable, get_userdata, StackGuard}; use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti, Value}; @@ -679,7 +680,7 @@ impl<'lua> AnyUserData<'lua> { // Lua 5.2/5.1 allows to store only a table. Then we will wrap the value. let t = lua.create_table()?; t.raw_set(1, v)?; - crate::Value::Table(t) + Value::Table(t) }; #[cfg(any(feature = "lua54", feature = "lua53"))] let v = v.to_lua(lua)?; @@ -702,13 +703,13 @@ impl<'lua> AnyUserData<'lua> { let lua = self.0.lua; let res = unsafe { let _sg = StackGuard::new(lua.state); - assert_stack(lua.state, 3); + assert_stack(lua.state, 2); lua.push_ref(&self.0); ffi::lua_getuservalue(lua.state, -1); lua.pop_value() }; #[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))] - return crate::Table::from_lua(res, lua)?.get(1); + return Table::from_lua(res, lua)?.get(1); #[cfg(any(feature = "lua54", feature = "lua53"))] V::from_lua(res, lua) } @@ -754,10 +755,9 @@ impl<'lua> AnyUserData<'lua> { unsafe { let lua = self.0.lua; let _sg = StackGuard::new(lua.state); - assert_stack(lua.state, 3); + assert_stack(lua.state, 2); lua.push_ref(&self.0); - if ffi::lua_getmetatable(lua.state, -1) == 0 { return Err(Error::UserDataTypeMismatch); } @@ -798,28 +798,26 @@ impl<'lua> AnyUserData<'lua> { assert_stack(lua.state, 3); lua.push_ref(&self.0); - if ffi::lua_getmetatable(lua.state, -1) == 0 { - Err(Error::UserDataTypeMismatch) - } else { - ffi::lua_rawgeti( - lua.state, - ffi::LUA_REGISTRYINDEX, - lua.userdata_metatable::<T>()? as ffi::lua_Integer, - ); - - if ffi::lua_rawequal(lua.state, -1, -2) == 0 { - // Maybe UserData destructed? - ffi::lua_pop(lua.state, 1); - get_destructed_userdata_metatable(lua.state); - if ffi::lua_rawequal(lua.state, -1, -2) == 1 { - Err(Error::UserDataDestructed) - } else { - Err(Error::UserDataTypeMismatch) - } + return Err(Error::UserDataTypeMismatch); + } + ffi::lua_rawgeti( + lua.state, + ffi::LUA_REGISTRYINDEX, + lua.userdata_metatable::<T>()? as Integer, + ); + + if ffi::lua_rawequal(lua.state, -1, -2) == 0 { + // Maybe UserData destructed? + ffi::lua_pop(lua.state, 1); + get_destructed_userdata_metatable(lua.state); + if ffi::lua_rawequal(lua.state, -1, -2) == 1 { + Err(Error::UserDataDestructed) } else { - func(&*get_userdata::<UserDataCell<T>>(lua.state, -3)) + Err(Error::UserDataTypeMismatch) } + } else { + func(&*get_userdata::<UserDataCell<T>>(lua.state, -3)) } } } @@ -918,17 +916,17 @@ impl<'lua> Serialize for AnyUserData<'lua> { where S: Serializer, { - let f = || unsafe { + let res = (|| unsafe { let lua = self.0.lua; let _sg = StackGuard::new(lua.state); - assert_stack(lua.state, 2); + assert_stack(lua.state, 3); lua.push_userdata_ref(&self.0)?; let ud = &*get_userdata::<UserDataCell<()>>(lua.state, -1); (*ud.try_borrow().map_err(|_| Error::UserDataBorrowError)?.ser) .serialize(serializer) .map_err(|err| Error::SerializeError(err.to_string())) - }; - f().map_err(ser::Error::custom) + })(); + res.map_err(ser::Error::custom) } } |