Skip to main content

luaur_vm/functions/
lua_d_rawrunprotected_ldo.rs

1//! Node: `cxx:Function:Luau.VM:VM/src/ldo.cpp:124:lua_d_rawrunprotected`
2//! Source: `VM/src/ldo.cpp:124-159` (hand-ported; C++-exceptions build
3//! flavor — `luaD_throw` is `panic_any(lua_exception)`, this is the matching
4//! `catch_unwind` boundary; see translation/design-cards/lvmexecute.md)
5
6use crate::enums::lua_status::lua_Status;
7use crate::functions::lua_g_pusherror::lua_g_pusherror;
8use crate::records::lua_exception::lua_exception;
9use crate::type_aliases::lua_state::lua_State;
10use crate::type_aliases::pfunc::Pfunc;
11use luaur_common::macros::luau_assert::LUAU_ASSERT;
12
13#[allow(non_snake_case)]
14pub unsafe fn luaD_rawrunprotected(
15    L: *mut lua_State,
16    f: Pfunc,
17    ud: *mut core::ffi::c_void,
18) -> core::ffi::c_int {
19    let mut status: core::ffi::c_int = 0;
20
21    // Silence the default panic-hook noise for the VM's longjmp-emulation
22    // unwinds (a caught `lua_exception` is a normal Lua error, not a crash).
23    crate::functions::install_lua_exception_panic_hook::install_lua_exception_panic_hook();
24
25    let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
26        if let Some(f) = f {
27            f(L, ud);
28        }
29    }));
30
31    if let Err(payload) = result {
32        if let Some(e) = payload.downcast_ref::<lua_exception>() {
33            // It is assumed/required that the exception caught here was
34            // thrown from the same Luau state (see C++ comment).
35            LUAU_ASSERT!(e.getThread() == L as *const lua_State);
36            status = e.getStatus();
37        } else {
38            // Luau will never throw this, but this can catch panics that
39            // escape from Rust implementations of external functions —
40            // the C++ `catch (std::exception&)` arm. Push the message so
41            // error handling below can proceed.
42            let msg: &str = if let Some(s) = payload.downcast_ref::<&str>() {
43                s
44            } else if let Some(s) = payload.downcast_ref::<alloc::string::String>() {
45                s.as_str()
46            } else {
47                "unknown error"
48            };
49            let cmsg = std::ffi::CString::new(msg)
50                .unwrap_or_else(|_| std::ffi::CString::new("invalid error message").unwrap());
51            // C++ nests a second try/catch for OOM while pushing; a Rust
52            // allocation failure aborts, so the LUA_ERRMEM arm has no analog.
53            lua_g_pusherror(L, cmsg.as_ptr());
54            status = lua_Status::LUA_ERRRUN as core::ffi::c_int;
55        }
56    }
57
58    status
59}
60
61#[allow(unused_imports)]
62pub use luaD_rawrunprotected as lua_d_rawrunprotected;