Skip to content

Commit

Permalink
Don't run GC finalizers on ref thread.
Browse files Browse the repository at this point in the history
If this happen then we don't have full access to the ref thread stack.
Fixes #491
  • Loading branch information
khvzak committed Nov 30, 2024
1 parent 7a3f19b commit 5fd96c7
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1043,8 +1043,8 @@ impl Lua {
let state = lua.state();
unsafe {
if lua.unlikely_memory_error() {
crate::util::push_buffer(lua.ref_thread(), buf.as_ref(), false)?;
return Ok(Buffer(lua.pop_ref_thread()));
crate::util::push_buffer(state, buf.as_ref(), false)?;
return Ok(Buffer(lua.pop_ref()));
}

let _sg = StackGuard::new(state);
Expand Down
14 changes: 9 additions & 5 deletions src/state/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,8 @@ impl RawLua {
pub(crate) unsafe fn create_string(&self, s: impl AsRef<[u8]>) -> Result<String> {
let state = self.state();
if self.unlikely_memory_error() {
push_string(self.ref_thread(), s.as_ref(), false)?;
return Ok(String(self.pop_ref_thread()));
push_string(state, s.as_ref(), false)?;
return Ok(String(self.pop_ref()));
}

let _sg = StackGuard::new(state);
Expand All @@ -444,12 +444,12 @@ impl RawLua {

/// See [`Lua::create_table_with_capacity`]
pub(crate) unsafe fn create_table_with_capacity(&self, narr: usize, nrec: usize) -> Result<Table> {
let state = self.state();
if self.unlikely_memory_error() {
push_table(self.ref_thread(), narr, nrec, false)?;
return Ok(Table(self.pop_ref_thread()));
push_table(state, narr, nrec, false)?;
return Ok(Table(self.pop_ref()));
}

let state = self.state();
let _sg = StackGuard::new(state);
check_stack(state, 3)?;
push_table(state, narr, nrec, true)?;
Expand Down Expand Up @@ -734,6 +734,10 @@ impl RawLua {

pub(crate) unsafe fn drop_ref(&self, vref: &ValueRef) {
let ref_thread = self.ref_thread();
mlua_debug_assert!(
ffi::lua_gettop(ref_thread) >= vref.index,
"GC finalizer is not allowed in ref_thread"
);
ffi::lua_pushnil(ref_thread);
ffi::lua_replace(ref_thread, vref.index);
(*self.extra.get()).ref_free.push(vref.index);
Expand Down
18 changes: 18 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1377,3 +1377,21 @@ fn test_exec_raw() -> Result<()> {

Ok(())
}

#[test]
fn test_gc_drop_ref_thread() -> Result<()> {
let lua = Lua::new();

let t = lua.create_table()?;
lua.create_function(move |_, ()| {
_ = &t;
Ok(())
})?;

for _ in 0..10000 {
// GC will run eventually to collect the function and the table above
lua.create_table()?;
}

Ok(())
}

0 comments on commit 5fd96c7

Please sign in to comment.