Skip to content

Commit a2615a8

Browse files
committed
Fix for a soundness bug around scope, don't allow callback parameters to escape
Also includes other fixes for compiletest_rs failures, and a small reorg of tests
1 parent 8366960 commit a2615a8

8 files changed

+152
-104
lines changed

src/scope.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ impl<'scope> Scope<'scope> {
6161
A: FromLuaMulti<'callback>,
6262
R: ToLuaMulti<'callback>,
6363
F: 'scope + Fn(&'callback Lua, A) -> Result<R>,
64+
'scope: 'callback,
6465
{
6566
unsafe {
6667
let f = Box::new(move |lua, args| {
@@ -106,6 +107,7 @@ impl<'scope> Scope<'scope> {
106107
A: FromLuaMulti<'callback>,
107108
R: ToLuaMulti<'callback>,
108109
F: 'scope + FnMut(&'callback Lua, A) -> Result<R>,
110+
'scope: 'callback,
109111
{
110112
let func = RefCell::new(func);
111113
self.create_function(move |lua, args| {

src/tests/mod.rs

Lines changed: 2 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
mod function;
2+
mod scope;
23
mod string;
34
mod table;
45
mod thread;
56
mod types;
67
mod userdata;
78

8-
use std::cell::Cell;
99
use std::iter::FromIterator;
1010
use std::panic::catch_unwind;
11-
use std::rc::Rc;
1211
use std::sync::Arc;
1312
use std::{error, fmt};
1413

15-
use {
16-
Error, ExternalError, Function, Lua, Nil, Result, String, Table, UserData, UserDataMethods,
17-
Value, Variadic,
18-
};
14+
use {Error, ExternalError, Function, Lua, Nil, Result, String, Table, UserData, Value, Variadic};
1915

2016
#[test]
2117
fn test_load() {
@@ -620,102 +616,6 @@ fn test_mismatched_registry_key() {
620616
};
621617
}
622618

623-
#[test]
624-
fn scope_func() {
625-
let lua = Lua::new();
626-
627-
let rc = Rc::new(Cell::new(0));
628-
lua.scope(|scope| {
629-
let r = rc.clone();
630-
let f = scope
631-
.create_function(move |_, ()| {
632-
r.set(42);
633-
Ok(())
634-
})
635-
.unwrap();
636-
lua.globals().set("bad", f.clone()).unwrap();
637-
f.call::<_, ()>(()).unwrap();
638-
assert_eq!(Rc::strong_count(&rc), 2);
639-
});
640-
assert_eq!(rc.get(), 42);
641-
assert_eq!(Rc::strong_count(&rc), 1);
642-
643-
match lua
644-
.globals()
645-
.get::<_, Function>("bad")
646-
.unwrap()
647-
.call::<_, ()>(())
648-
{
649-
Err(Error::CallbackError { .. }) => {}
650-
r => panic!("improper return for destructed function: {:?}", r),
651-
};
652-
}
653-
654-
#[test]
655-
fn scope_drop() {
656-
let lua = Lua::new();
657-
658-
struct MyUserdata(Rc<()>);
659-
impl UserData for MyUserdata {
660-
fn add_methods(methods: &mut UserDataMethods<Self>) {
661-
methods.add_method("method", |_, _, ()| Ok(()));
662-
}
663-
}
664-
665-
let rc = Rc::new(());
666-
667-
lua.scope(|scope| {
668-
lua.globals()
669-
.set(
670-
"test",
671-
scope.create_userdata(MyUserdata(rc.clone())).unwrap(),
672-
)
673-
.unwrap();
674-
assert_eq!(Rc::strong_count(&rc), 2);
675-
});
676-
assert_eq!(Rc::strong_count(&rc), 1);
677-
678-
match lua.exec::<()>("test:method()", None) {
679-
Err(Error::CallbackError { .. }) => {}
680-
r => panic!("improper return for destructed userdata: {:?}", r),
681-
};
682-
}
683-
684-
#[test]
685-
fn scope_capture() {
686-
let lua = Lua::new();
687-
688-
let mut i = 0;
689-
lua.scope(|scope| {
690-
scope
691-
.create_function_mut(|_, ()| {
692-
i = 42;
693-
Ok(())
694-
})
695-
.unwrap()
696-
.call::<_, ()>(())
697-
.unwrap();
698-
});
699-
assert_eq!(i, 42);
700-
}
701-
702-
#[test]
703-
fn outer_lua_access() {
704-
let lua = Lua::new();
705-
let table = lua.create_table().unwrap();
706-
lua.scope(|scope| {
707-
scope
708-
.create_function_mut(|_, ()| {
709-
table.set("a", "b").unwrap();
710-
Ok(())
711-
})
712-
.unwrap()
713-
.call::<_, ()>(())
714-
.unwrap();
715-
});
716-
assert_eq!(table.get::<_, String>("a").unwrap(), "b");
717-
}
718-
719619
#[test]
720620
fn too_many_returns() {
721621
let lua = Lua::new();

src/tests/scope.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use std::cell::Cell;
2+
use std::rc::Rc;
3+
4+
use {Error, Function, Lua, String, UserData, UserDataMethods};
5+
6+
#[test]
7+
fn scope_func() {
8+
let lua = Lua::new();
9+
10+
let rc = Rc::new(Cell::new(0));
11+
lua.scope(|scope| {
12+
let r = rc.clone();
13+
let f = scope
14+
.create_function(move |_, ()| {
15+
r.set(42);
16+
Ok(())
17+
})
18+
.unwrap();
19+
lua.globals().set("bad", f.clone()).unwrap();
20+
f.call::<_, ()>(()).unwrap();
21+
assert_eq!(Rc::strong_count(&rc), 2);
22+
});
23+
assert_eq!(rc.get(), 42);
24+
assert_eq!(Rc::strong_count(&rc), 1);
25+
26+
match lua
27+
.globals()
28+
.get::<_, Function>("bad")
29+
.unwrap()
30+
.call::<_, ()>(())
31+
{
32+
Err(Error::CallbackError { .. }) => {}
33+
r => panic!("improper return for destructed function: {:?}", r),
34+
};
35+
}
36+
37+
#[test]
38+
fn scope_drop() {
39+
let lua = Lua::new();
40+
41+
struct MyUserdata(Rc<()>);
42+
impl UserData for MyUserdata {
43+
fn add_methods(methods: &mut UserDataMethods<Self>) {
44+
methods.add_method("method", |_, _, ()| Ok(()));
45+
}
46+
}
47+
48+
let rc = Rc::new(());
49+
50+
lua.scope(|scope| {
51+
lua.globals()
52+
.set(
53+
"test",
54+
scope.create_userdata(MyUserdata(rc.clone())).unwrap(),
55+
)
56+
.unwrap();
57+
assert_eq!(Rc::strong_count(&rc), 2);
58+
});
59+
assert_eq!(Rc::strong_count(&rc), 1);
60+
61+
match lua.exec::<()>("test:method()", None) {
62+
Err(Error::CallbackError { .. }) => {}
63+
r => panic!("improper return for destructed userdata: {:?}", r),
64+
};
65+
}
66+
67+
#[test]
68+
fn scope_capture() {
69+
let lua = Lua::new();
70+
71+
let mut i = 0;
72+
lua.scope(|scope| {
73+
scope
74+
.create_function_mut(|_, ()| {
75+
i = 42;
76+
Ok(())
77+
})
78+
.unwrap()
79+
.call::<_, ()>(())
80+
.unwrap();
81+
});
82+
assert_eq!(i, 42);
83+
}
84+
85+
#[test]
86+
fn outer_lua_access() {
87+
let lua = Lua::new();
88+
let table = lua.create_table().unwrap();
89+
lua.scope(|scope| {
90+
scope
91+
.create_function_mut(|_, ()| {
92+
table.set("a", "b").unwrap();
93+
Ok(())
94+
})
95+
.unwrap()
96+
.call::<_, ()>(())
97+
.unwrap();
98+
});
99+
assert_eq!(table.get::<_, String>("a").unwrap(), "b");
100+
}

tests/compile-fail/not_refunwindsafe.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ use rlua::*;
77
fn main() {
88
let lua = Lua::new();
99
let _ = catch_unwind(|| lua.create_table().unwrap());
10-
//~^ error: the trait bound `std::cell::UnsafeCell<()>: std::panic::RefUnwindSafe` is not satisfied in `rlua::Lua`
10+
//~^ error: the type `std::cell::UnsafeCell<()>` may contain interior mutability and a reference
11+
// may not be safely transferrable across a catch_unwind boundary
1112
}

tests/compile-fail/ref_not_unwindsafe.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ fn main() {
88
let lua = Lua::new();
99
let table = lua.create_table().unwrap();
1010
let _ = catch_unwind(move || table.set("a", "b").unwrap());
11-
//~^ error: the trait bound `std::cell::UnsafeCell<()>: std::panic::RefUnwindSafe` is not satisfied in `rlua::Lua`
11+
//~^ error: the type `std::cell::UnsafeCell<()>` may contain interior mutability and a reference
12+
// may not be safely transferrable across a catch_unwind boundary
1213
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
extern crate rlua;
2+
3+
use rlua::*;
4+
5+
fn main() {
6+
struct Test {
7+
field: i32,
8+
}
9+
10+
let lua = Lua::new();
11+
let mut outer: Option<Table> = None;
12+
lua.scope(|scope| {
13+
let f = scope
14+
.create_function_mut(|_, t: Table| {
15+
outer = Some(t);
16+
//~^ error: `*outer` does not live long enough
17+
Ok(())
18+
})
19+
.unwrap();
20+
f.call::<_, ()>(lua.create_table()).unwrap();
21+
});
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
extern crate rlua;
2+
3+
use rlua::*;
4+
5+
fn main() {
6+
struct Test {
7+
field: i32,
8+
}
9+
10+
let lua = Lua::new();
11+
lua.scope(|scope| {
12+
let mut inner: Option<Table> = None;
13+
let f = scope
14+
.create_function_mut(|_, t: Table| {
15+
inner = Some(t);
16+
//~^ error: `inner` does not live long enough
17+
Ok(())
18+
})
19+
.unwrap();
20+
f.call::<_, ()>(lua.create_table()).unwrap();
21+
});
22+
}

0 commit comments

Comments
 (0)