Solve (maybe) *another* soundness issue with `Lua::scope`
Callbacks should not be able to capture their arguments and hold onto them, because the `&Lua` used in previous calls will not remain valid across calls. One could imagine an API where the specific `&Lua` is simply stored inside the `Scope` itself, but this is harder to do, and would (badly) encourage storing references inside Lua userdata. Ideally, the only way it should be possible to store Lua handles inside Lua itself is through usafety or the `rental` crate or other self-borrowing techniques to make references into 'static types. If at all possible this roadblock should stay, because reference types inside userdata are almost always going to lead to a a memory leak, and if you accept the risks you should just use `RegistryKey` with its manual removal.
This commit is contained in:
parent
b35ff5fa12
commit
1a9c50f228
14
src/scope.rs
14
src/scope.rs
|
@ -43,15 +43,15 @@ impl<'scope> Scope<'scope> {
|
|||
/// [`Lua::scope`]: struct.Lua.html#method.scope
|
||||
pub fn create_function<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
|
||||
where
|
||||
A: FromLuaMulti<'scope>,
|
||||
R: ToLuaMulti<'scope>,
|
||||
F: 'scope + Fn(&'scope Lua, A) -> Result<R>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'scope + Fn(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
unsafe {
|
||||
let f = Box::new(move |lua, args| {
|
||||
func(lua, A::from_lua_multi(args, lua)?)?.to_lua_multi(lua)
|
||||
});
|
||||
let f = mem::transmute::<Callback<'scope, 'scope>, Callback<'scope, 'static>>(f);
|
||||
let f = mem::transmute::<Callback<'lua, 'scope>, Callback<'lua, 'static>>(f);
|
||||
let f = self.lua.create_callback(f)?;
|
||||
|
||||
let mut destructors = self.destructors.borrow_mut();
|
||||
|
@ -85,9 +85,9 @@ impl<'scope> Scope<'scope> {
|
|||
/// [`Scope::create_function`]: #method.create_function
|
||||
pub fn create_function_mut<'lua, A, R, F>(&'lua self, func: F) -> Result<Function<'lua>>
|
||||
where
|
||||
A: FromLuaMulti<'scope>,
|
||||
R: ToLuaMulti<'scope>,
|
||||
F: 'scope + FnMut(&'scope Lua, A) -> Result<R>,
|
||||
A: FromLuaMulti<'lua>,
|
||||
R: ToLuaMulti<'lua>,
|
||||
F: 'scope + FnMut(&'lua Lua, A) -> Result<R>,
|
||||
{
|
||||
let func = RefCell::new(func);
|
||||
self.create_function(move |lua, args| {
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
extern crate rlua;
|
||||
|
||||
use rlua::*;
|
||||
|
||||
fn main() {
|
||||
struct Test {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
let lua = Lua::new();
|
||||
lua.scope(|scope| {
|
||||
let mut inner: Option<Table> = None;
|
||||
let f = scope
|
||||
.create_function_mut(move |lua, t: Table| {
|
||||
//~^ error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
|
||||
if let Some(old) = inner.take() {
|
||||
// Access old callback `Lua`.
|
||||
}
|
||||
inner = Some(t);
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
f.call::<_, ()>(lua.create_table()).unwrap();
|
||||
});
|
||||
}
|
|
@ -12,8 +12,8 @@ fn main() {
|
|||
lua.scope(|scope| {
|
||||
let f = scope
|
||||
.create_function_mut(|_, t: Table| {
|
||||
//~^^ error: borrowed data cannot be stored outside of its closure
|
||||
outer = Some(t);
|
||||
//~^ error: `*outer` does not live long enough
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
|
|
|
@ -12,8 +12,8 @@ fn main() {
|
|||
let mut inner: Option<Table> = None;
|
||||
let f = scope
|
||||
.create_function_mut(|_, t: Table| {
|
||||
//~^ error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
|
||||
inner = Some(t);
|
||||
//~^ error: `inner` does not live long enough
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
|
|
Loading…
Reference in New Issue