Skip to content

Commit f539f60

Browse files
committed
Fix Function::deep_clone() method (Luau).
The `lua_clonefunction` function can fail (and trigger GC) so we need to return Result instead of allowing longjmp
1 parent aa187e6 commit f539f60

File tree

2 files changed

+16
-8
lines changed

2 files changed

+16
-8
lines changed

src/function.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -492,16 +492,24 @@ impl Function {
492492
/// This function returns shallow clone (same handle) for Rust/C functions.
493493
#[cfg(any(feature = "luau", doc))]
494494
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
495-
pub fn deep_clone(&self) -> Self {
495+
pub fn deep_clone(&self) -> Result<Self> {
496496
let lua = self.0.lua.lock();
497-
let ref_thread = lua.ref_thread();
497+
let state = lua.state();
498498
unsafe {
499-
if ffi::lua_iscfunction(ref_thread, self.0.index) != 0 {
500-
return self.clone();
499+
let _sg = StackGuard::new(state);
500+
check_stack(state, 2)?;
501+
502+
lua.push_ref(&self.0);
503+
if ffi::lua_iscfunction(state, -1) != 0 {
504+
return Ok(self.clone());
501505
}
502506

503-
ffi::lua_clonefunction(ref_thread, self.0.index);
504-
Function(lua.pop_ref_thread())
507+
if lua.unlikely_memory_error() {
508+
ffi::lua_clonefunction(state, -1);
509+
} else {
510+
protect_lua!(state, 1, 1, fn(state) ffi::lua_clonefunction(state, -1))?;
511+
}
512+
Ok(Function(lua.pop_ref()))
505513
}
506514
}
507515
}

tests/function.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,15 +306,15 @@ fn test_function_deep_clone() -> Result<()> {
306306

307307
lua.globals().set("a", 1)?;
308308
let func1 = lua.load("a += 1; return a").into_function()?;
309-
let func2 = func1.deep_clone();
309+
let func2 = func1.deep_clone()?;
310310

311311
assert_ne!(func1.to_pointer(), func2.to_pointer());
312312
assert_eq!(func1.call::<i32>(())?, 2);
313313
assert_eq!(func2.call::<i32>(())?, 3);
314314

315315
// Check that for Rust functions deep_clone is just a clone
316316
let rust_func = lua.create_function(|_, ()| Ok(42))?;
317-
let rust_func2 = rust_func.deep_clone();
317+
let rust_func2 = rust_func.deep_clone()?;
318318
assert_eq!(rust_func.to_pointer(), rust_func2.to_pointer());
319319

320320
Ok(())

0 commit comments

Comments
 (0)