Don't panic on mismatched `RegistryKey` use, instead return error

This commit is contained in:
kyren 2018-02-06 10:51:39 -05:00
parent 823c2deaca
commit b056ed2c4e
3 changed files with 20 additions and 15 deletions

View File

@ -87,6 +87,8 @@ pub enum Error {
/// [`AnyUserData`]: struct.AnyUserData.html
/// [`UserData`]: trait.UserData.html
UserDataBorrowMutError,
/// A `RegistryKey` produced from a different Lua state was used.
MismatchedRegistryKey,
/// A Rust callback returned `Err`, raising the contained `Error` as a Lua error.
CallbackError {
/// Lua call stack backtrace.
@ -142,6 +144,9 @@ impl fmt::Display for Error {
Error::UserDataTypeMismatch => write!(fmt, "userdata is not expected type"),
Error::UserDataBorrowError => write!(fmt, "userdata already mutably borrowed"),
Error::UserDataBorrowMutError => write!(fmt, "userdata already borrowed"),
Error::MismatchedRegistryKey => {
write!(fmt, "RegistryKey used from different Lua state")
}
Error::CallbackError { ref traceback, .. } => {
write!(fmt, "callback error: {}", traceback)
}

View File

@ -504,11 +504,9 @@ impl Lua {
/// value previously placed by `create_registry_value`.
pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> {
unsafe {
lua_assert!(
self.state,
Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list),
"Lua instance passed RegistryKey created from a different Lua"
);
if !Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list) {
return Err(Error::MismatchedRegistryKey);
}
stack_err_guard(self.state, 0, || {
check_stack(self.state, 1);
@ -528,25 +526,25 @@ impl Lua {
/// `create_registry_value`. In addition to manual `RegistryKey` removal, you can also call
/// `expire_registry_values` to automatically remove values from the registry whose
/// `RegistryKey`s have been dropped.
pub fn remove_registry_value(&self, mut key: RegistryKey) {
pub fn remove_registry_value(&self, mut key: RegistryKey) -> Result<()> {
unsafe {
lua_assert!(
self.state,
Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list),
"Lua instance passed RegistryKey created from a different Lua"
);
if !Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list) {
return Err(Error::MismatchedRegistryKey);
}
ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, key.registry_id);
// Don't adding to the registry drop list when dropping the key
key.registry_id = ffi::LUA_REFNIL;
Ok(())
}
}
/// Returns true if the given `RegistryKey` was created by a `Lua` which shares the underlying
/// main state with this `Lua` instance.
///
/// Other than this, methods that accept a `RegistryKey` will panic if passed a `RegistryKey`
/// that was not created with a matching `Lua` state.
/// Other than this, methods that accept a `RegistryKey` will return
/// `Error::MismatchedRegistryKey` if passed a `RegistryKey` that was not created with a
/// matching `Lua` state.
pub fn owns_registry_value(&self, key: &RegistryKey) -> bool {
unsafe { Arc::ptr_eq(&key.drop_list, &(*self.extra()).registry_drop_list) }
}

View File

@ -586,13 +586,15 @@ fn test_lua_registry_ownership() {
}
#[test]
#[should_panic]
fn test_mismatched_registry_key() {
let lua1 = Lua::new();
let lua2 = Lua::new();
let r = lua1.create_registry_value("hello").unwrap();
lua2.remove_registry_value(r);
match lua2.remove_registry_value(r) {
Err(Error::MismatchedRegistryKey) => {}
r => panic!("wrong result type for mismatched registry key, {:?}", r),
};
}
// TODO: Need to use compiletest-rs or similar to make sure these don't compile.