Skip to content

Commit ced808d

Browse files
committed
Don't trigger longjmp in rust.
Motivation behind this change is upcoming breaking change in Rust compiler v1.52.0 to prevent unwinding across FFI boundaries. rust-lang/rust#76570 The new functionality requires nightly compiler to declare FFI functions as "C-unwind". The fundamental solution is to use C shim to wrap "e" and "m" Lua functions in pcall. Additionally define Rust calling convention to trigger lua_error on Rust behalf.
1 parent c95ac32 commit ced808d

19 files changed

+2538
-851
lines changed

build/main.rs

+9
Original file line numberDiff line numberDiff line change
@@ -239,5 +239,14 @@ fn main() {
239239
println!("cargo:rerun-if-changed=src/ffi/glue/glue.c");
240240
}
241241

242+
let mut shim_cc = cc::Build::new();
243+
shim_cc
244+
.include(include_dir)
245+
.define("COMPAT53_INCLUDE_SOURCE", None);
246+
#[cfg(feature = "luajit")]
247+
shim_cc.define("COMPAT53_LUAJIT", None);
248+
shim_cc.file("src/ffi/shim/shim.c").compile("shim");
249+
250+
println!("cargo:rerun-if-changed=src/ffi/shim");
242251
println!("cargo:rerun-if-changed=build");
243252
}

src/ffi/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,5 @@ mod lauxlib;
288288
mod lua;
289289
mod luaconf;
290290
mod lualib;
291+
292+
pub mod safe;

src/ffi/safe.rs

+265
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
use std::ffi::CString;
2+
use std::os::raw::{c_char, c_int, c_void};
3+
4+
use crate::error::Result;
5+
use crate::util::protect_lua;
6+
7+
use super::lua::{lua_CFunction, lua_Debug, lua_Integer, lua_State};
8+
9+
extern "C" {
10+
#[link_name = "MLUA_WRAPPED_ERROR_SIZE"]
11+
pub static mut WRAPPED_ERROR_SIZE: usize;
12+
#[link_name = "MLUA_WRAPPED_PANIC_SIZE"]
13+
pub static mut WRAPPED_PANIC_SIZE: usize;
14+
#[link_name = "MLUA_WRAPPED_ERROR_KEY"]
15+
pub static mut WRAPPED_ERROR_KEY: *const c_void;
16+
#[link_name = "MLUA_WRAPPED_PANIC_KEY"]
17+
pub static mut WRAPPED_PANIC_KEY: *const c_void;
18+
19+
pub fn lua_call_mlua_hook_proc(L: *mut lua_State, ar: *mut lua_Debug);
20+
21+
pub fn meta_index_impl(state: *mut lua_State) -> c_int;
22+
pub fn meta_newindex_impl(state: *mut lua_State) -> c_int;
23+
pub fn bind_call_impl(state: *mut lua_State) -> c_int;
24+
pub fn error_traceback(state: *mut lua_State) -> c_int;
25+
26+
fn lua_gc_s(L: *mut lua_State) -> c_int;
27+
fn luaL_ref_s(L: *mut lua_State) -> c_int;
28+
fn lua_pushlstring_s(L: *mut lua_State) -> c_int;
29+
fn lua_tolstring_s(L: *mut lua_State) -> c_int;
30+
fn lua_newthread_s(L: *mut lua_State) -> c_int;
31+
fn lua_newuserdata_s(L: *mut lua_State) -> c_int;
32+
fn lua_pushcclosure_s(L: *mut lua_State) -> c_int;
33+
fn lua_pushrclosure_s(L: *mut lua_State) -> c_int;
34+
fn luaL_requiref_s(L: *mut lua_State) -> c_int;
35+
fn error_traceback_s(L: *mut lua_State) -> c_int;
36+
37+
fn lua_createtable_s(L: *mut lua_State) -> c_int;
38+
fn lua_gettable_s(L: *mut lua_State) -> c_int;
39+
fn lua_settable_s(L: *mut lua_State) -> c_int;
40+
fn lua_geti_s(L: *mut lua_State) -> c_int;
41+
fn lua_rawset_s(L: *mut lua_State) -> c_int;
42+
fn lua_rawseti_s(L: *mut lua_State) -> c_int;
43+
fn lua_rawsetp_s(L: *mut lua_State) -> c_int;
44+
fn lua_rawsetfield_s(L: *mut lua_State) -> c_int;
45+
fn lua_rawinsert_s(L: *mut lua_State) -> c_int;
46+
fn lua_rawremove_s(L: *mut lua_State) -> c_int;
47+
fn luaL_len_s(L: *mut lua_State) -> c_int;
48+
fn lua_next_s(L: *mut lua_State) -> c_int;
49+
}
50+
51+
#[repr(C)]
52+
struct StringArg {
53+
data: *const c_char,
54+
len: usize,
55+
}
56+
57+
//
58+
// Common functions
59+
//
60+
61+
// Uses 4 stack spaces
62+
pub unsafe fn lua_gc(state: *mut lua_State, what: c_int, data: c_int) -> Result<c_int> {
63+
super::lua_pushinteger(state, what as lua_Integer);
64+
super::lua_pushinteger(state, data as lua_Integer);
65+
protect_lua(state, 2, lua_gc_s)?;
66+
let ret = super::lua_tointeger(state, -1) as c_int;
67+
super::lua_pop(state, 1);
68+
Ok(ret)
69+
}
70+
71+
// Uses 3 stack spaces
72+
pub unsafe fn luaL_ref(state: *mut lua_State, table: c_int) -> Result<c_int> {
73+
super::lua_pushvalue(state, table);
74+
super::lua_rotate(state, -2, 1);
75+
protect_lua(state, 2, luaL_ref_s)?;
76+
let ret = super::lua_tointeger(state, -1) as c_int;
77+
super::lua_pop(state, 1);
78+
Ok(ret)
79+
}
80+
81+
// Uses 3 stack spaces
82+
pub unsafe fn lua_pushstring<S: AsRef<[u8]> + ?Sized>(state: *mut lua_State, s: &S) -> Result<()> {
83+
let s = s.as_ref();
84+
let s = StringArg {
85+
data: s.as_ptr() as *const c_char,
86+
len: s.len(),
87+
};
88+
super::lua_pushlightuserdata(state, &s as *const StringArg as *mut c_void);
89+
protect_lua(state, 1, lua_pushlstring_s)
90+
}
91+
92+
// Uses 4 stack spaces
93+
pub unsafe fn lua_tolstring(
94+
state: *mut lua_State,
95+
index: c_int,
96+
len: *mut usize,
97+
) -> Result<*const c_char> {
98+
let index = super::lua_absindex(state, index);
99+
super::lua_pushvalue(state, index);
100+
super::lua_pushlightuserdata(state, len as *mut c_void);
101+
protect_lua(state, 2, lua_tolstring_s)?;
102+
let s = super::lua_touserdata(state, -1);
103+
super::lua_pop(state, 1);
104+
super::lua_replace(state, index);
105+
Ok(s as *const c_char)
106+
}
107+
108+
// Uses 2 stack spaces
109+
pub unsafe fn lua_newthread(state: *mut lua_State) -> Result<*mut lua_State> {
110+
protect_lua(state, 0, lua_newthread_s)?;
111+
Ok(super::lua_tothread(state, -1))
112+
}
113+
114+
// Uses 3 stack spaces
115+
pub unsafe fn lua_newuserdata(state: *mut lua_State, size: usize) -> Result<*mut c_void> {
116+
super::lua_pushinteger(state, size as lua_Integer);
117+
protect_lua(state, 1, lua_newuserdata_s)?;
118+
Ok(super::lua_touserdata(state, -1))
119+
}
120+
121+
// Uses 4 stack spaces
122+
pub unsafe fn lua_pushcclosure(state: *mut lua_State, f: lua_CFunction, n: c_int) -> Result<()> {
123+
super::lua_pushlightuserdata(state, f as *mut c_void);
124+
super::lua_pushinteger(state, n as lua_Integer);
125+
protect_lua(state, n + 2, lua_pushcclosure_s)
126+
}
127+
128+
// Uses 4 stack spaces
129+
pub unsafe fn lua_pushrclosure(state: *mut lua_State, f: lua_CFunction, n: c_int) -> Result<()> {
130+
super::lua_pushlightuserdata(state, f as *mut c_void);
131+
if n > 0 {
132+
super::lua_rotate(state, -n - 1, 1);
133+
}
134+
super::lua_pushinteger(state, n as lua_Integer + 1);
135+
protect_lua(state, n + 2, lua_pushrclosure_s)
136+
}
137+
138+
// Uses 5 stack spaces
139+
pub unsafe fn luaL_requiref<S: AsRef<[u8]> + ?Sized>(
140+
state: *mut lua_State,
141+
modname: &S,
142+
openf: lua_CFunction,
143+
glb: c_int,
144+
) -> Result<()> {
145+
let modname = mlua_expect!(CString::new(modname.as_ref()), "modname contains nil bytes");
146+
super::lua_pushlightuserdata(state, modname.as_ptr() as *mut c_void);
147+
super::lua_pushlightuserdata(state, openf as *mut c_void);
148+
super::lua_pushinteger(state, glb as lua_Integer);
149+
protect_lua(state, 3, luaL_requiref_s)
150+
}
151+
152+
// Uses 3 stack spaces
153+
pub unsafe fn error_traceback2(state: *mut lua_State, state2: *mut lua_State) -> Result<()> {
154+
mlua_assert!(
155+
state != state2,
156+
"error_traceback2 must be used with two different states"
157+
);
158+
super::lua_pushlightuserdata(state, state2);
159+
protect_lua(state, 1, error_traceback_s)
160+
}
161+
162+
//
163+
// Table functions
164+
//
165+
166+
// Uses 4 stack spaces
167+
pub unsafe fn lua_createtable(state: *mut lua_State, narr: c_int, nrec: c_int) -> Result<()> {
168+
super::lua_pushinteger(state, narr as lua_Integer);
169+
super::lua_pushinteger(state, nrec as lua_Integer);
170+
protect_lua(state, 2, lua_createtable_s)
171+
}
172+
173+
// Uses 3 stack spaces
174+
pub unsafe fn lua_gettable(state: *mut lua_State, table: c_int) -> Result<()> {
175+
super::lua_pushvalue(state, table);
176+
super::lua_rotate(state, -2, 1);
177+
protect_lua(state, 2, lua_gettable_s)
178+
}
179+
180+
// Uses 3 stack spaces
181+
pub unsafe fn lua_settable(state: *mut lua_State, table: c_int) -> Result<()> {
182+
super::lua_pushvalue(state, table);
183+
super::lua_rotate(state, -3, 1);
184+
protect_lua(state, 3, lua_settable_s)
185+
}
186+
187+
// Uses 4 stack spaces
188+
pub unsafe fn lua_geti(state: *mut lua_State, table: c_int, i: lua_Integer) -> Result<c_int> {
189+
super::lua_pushvalue(state, table);
190+
super::lua_pushinteger(state, i);
191+
protect_lua(state, 2, lua_geti_s).map(|_| super::lua_type(state, -1))
192+
}
193+
194+
// Uses 3 stack spaces
195+
pub unsafe fn lua_rawset(state: *mut lua_State, table: c_int) -> Result<()> {
196+
super::lua_pushvalue(state, table);
197+
super::lua_rotate(state, -3, 1);
198+
protect_lua(state, 3, lua_rawset_s)
199+
}
200+
201+
// Uses 4 stack spaces
202+
pub unsafe fn lua_rawseti(state: *mut lua_State, table: c_int, i: lua_Integer) -> Result<()> {
203+
super::lua_pushvalue(state, table);
204+
super::lua_rotate(state, -2, 1);
205+
super::lua_pushinteger(state, i);
206+
protect_lua(state, 3, lua_rawseti_s)
207+
}
208+
209+
// Uses 4 stack spaces
210+
pub unsafe fn lua_rawsetp(state: *mut lua_State, table: c_int, ptr: *const c_void) -> Result<()> {
211+
super::lua_pushvalue(state, table);
212+
super::lua_rotate(state, -2, 1);
213+
super::lua_pushlightuserdata(state, ptr as *mut c_void);
214+
protect_lua(state, 3, lua_rawsetp_s)
215+
}
216+
217+
// Uses 4 stack spaces
218+
pub unsafe fn lua_rawsetfield<S>(state: *mut lua_State, table: c_int, field: &S) -> Result<()>
219+
where
220+
S: AsRef<[u8]> + ?Sized,
221+
{
222+
let field = field.as_ref();
223+
let s = StringArg {
224+
data: field.as_ptr() as *const c_char,
225+
len: field.len(),
226+
};
227+
super::lua_pushvalue(state, table);
228+
super::lua_pushlightuserdata(state, &s as *const StringArg as *mut c_void);
229+
super::lua_rotate(state, -3, 2);
230+
protect_lua(state, 3, lua_rawsetfield_s)
231+
}
232+
233+
// Uses 4 stack spaces
234+
pub unsafe fn lua_rawinsert(state: *mut lua_State, table: c_int, i: lua_Integer) -> Result<()> {
235+
super::lua_pushvalue(state, table);
236+
super::lua_rotate(state, -2, 1);
237+
super::lua_pushinteger(state, i);
238+
protect_lua(state, 3, lua_rawinsert_s)
239+
}
240+
241+
// Uses 4 stack spaces
242+
pub unsafe fn lua_rawremove(state: *mut lua_State, table: c_int, i: lua_Integer) -> Result<()> {
243+
super::lua_pushvalue(state, table);
244+
super::lua_pushinteger(state, i);
245+
protect_lua(state, 2, lua_rawremove_s)
246+
}
247+
248+
// Uses 3 stack spaces
249+
pub unsafe fn luaL_len(state: *mut lua_State, table: c_int) -> Result<lua_Integer> {
250+
super::lua_pushvalue(state, table);
251+
protect_lua(state, 1, luaL_len_s)?;
252+
let ret = super::lua_tointeger(state, -1);
253+
super::lua_pop(state, 1);
254+
Ok(ret)
255+
}
256+
257+
// Uses 3 stack spaces
258+
pub unsafe fn lua_next(state: *mut lua_State, table: c_int) -> Result<lua_Integer> {
259+
super::lua_pushvalue(state, table);
260+
super::lua_rotate(state, -2, 1);
261+
protect_lua(state, 2, lua_next_s)?;
262+
let ret = super::lua_tointeger(state, -1);
263+
super::lua_pop(state, 1);
264+
Ok(ret)
265+
}

0 commit comments

Comments
 (0)