summaryrefslogtreecommitdiff
path: root/src/userdata.rs
diff options
context:
space:
mode:
authorAlex Orlenko <zxteam@protonmail.com>2021-04-09 12:05:03 +0100
committerAlex Orlenko <zxteam@protonmail.com>2021-04-27 00:29:38 +0100
commitced808d5ab5777abf283a72f71c51ef8040b02f0 (patch)
tree52d97b5819f73f284886391943dee7e45e3b1b4b /src/userdata.rs
parentc95ac32741d121652bd895730b2eb67fb5c2cef3 (diff)
downloadmlua-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.rs56
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)
}
}