Skip to content

Commit 0b76fbd

Browse files
committed
WIP longjmp-free rlua
Mostly what's left is wrapping a lot of existing callbacks, and a lot of cleanup
1 parent 0450c9b commit 0b76fbd

File tree

11 files changed

+721
-408
lines changed

11 files changed

+721
-408
lines changed

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ default = ["builtin-lua"]
2121
# * LUA_INTEGER is long long
2222
# * LUA_NUMBER as double
2323
# * LUA_EXTRASPACE is sizeof(void*)
24-
builtin-lua = ["gcc"]
24+
# * LUAI_MAXSTACK is 1000000
25+
builtin-lua = []
2526

2627
[dependencies]
2728
libc = { version = "0.2" }
2829
failure = { version = "0.1.1" }
2930
compiletest_rs = { version = "0.3", optional = true }
3031

3132
[build-dependencies]
32-
gcc = { version = "0.3.52", optional = true }
33-
rustc_version = { version = "0.2" }
33+
gcc = { version = "0.3.52" }
3434

3535
[dev-dependencies]
3636
rustyline = "1.0.0"

build.rs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
#[cfg(feature = "builtin-lua")]
21
extern crate gcc;
3-
extern crate rustc_version;
42

53
use std::env;
64

75
fn main() {
86
let target_os = env::var("CARGO_CFG_TARGET_OS");
97
let target_family = env::var("CARGO_CFG_TARGET_FAMILY");
10-
if target_family == Ok("windows".to_string())
11-
&& rustc_version::version().unwrap() == rustc_version::Version::parse("1.24.0").unwrap()
12-
{
8+
9+
if target_family == Ok("windows".to_string()) {
1310
// Error handling is completely broken on windows with
1411
// https://github.com/rust-lang/rust/pull/46833 merged, and this includes stable rustc
1512
// 1.24.0+. `#[unwind]` fixes error handling on windows, but requires nightly! This
@@ -22,23 +19,25 @@ fn main() {
2219
println!("cargo:rustc-cfg=unwind");
2320
}
2421

25-
#[cfg(feature = "builtin-lua")]
26-
{
27-
let mut config = gcc::Build::new();
22+
let mut config = gcc::Build::new();
23+
24+
if target_os == Ok("linux".to_string()) {
25+
config.define("LUA_USE_LINUX", None);
26+
} else if target_os == Ok("macos".to_string()) {
27+
config.define("LUA_USE_MACOSX", None);
28+
} else if target_family == Ok("unix".to_string()) {
29+
config.define("LUA_USE_POSIX", None);
30+
} else if target_family == Ok("windows".to_string()) {
31+
config.define("LUA_USE_WINDOWS", None);
32+
}
2833

29-
if target_os == Ok("linux".to_string()) {
30-
config.define("LUA_USE_LINUX", None);
31-
} else if target_os == Ok("macos".to_string()) {
32-
config.define("LUA_USE_MACOSX", None);
33-
} else if target_family == Ok("unix".to_string()) {
34-
config.define("LUA_USE_POSIX", None);
35-
} else if target_family == Ok("windows".to_string()) {
36-
config.define("LUA_USE_WINDOWS", None);
37-
}
34+
if cfg!(debug_assertions) {
35+
config.define("LUA_USE_APICHECK", None);
36+
}
3837

39-
if cfg!(debug_assertions) {
40-
config.define("LUA_USE_APICHECK", None);
41-
}
38+
#[cfg(feature = "builtin-lua")]
39+
{
40+
let mut config = config.clone();
4241

4342
config
4443
.include("lua")
@@ -77,4 +76,11 @@ fn main() {
7776
.file("lua/lzio.c")
7877
.compile("liblua5.3.a");
7978
}
79+
80+
config
81+
.include("lua")
82+
.include("cbits")
83+
.file("cbits/macros.c")
84+
.file("cbits/safe.c")
85+
.compile("librlua_cbits.a");
8086
}

cbits/macros.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include "lua.h"
2+
#include "lauxlib.h"
3+
4+
void (lua_pop)(lua_State* state, int n) {
5+
lua_pop(state, n);
6+
}
7+
8+
void (lua_newtable)(lua_State* state) {
9+
lua_newtable(state);
10+
}
11+
12+
void (lua_pushcfunction)(lua_State* state, lua_CFunction function) {
13+
lua_pushcfunction(state, function);
14+
}
15+
16+
lua_Number (lua_tonumber)(lua_State* state, int index) {
17+
return lua_tonumber(state, index);
18+
}
19+
20+
lua_Integer (lua_tointeger)(lua_State* state, int index) {
21+
return lua_tointeger(state, index);
22+
}
23+
24+
char const* (lua_tostring)(lua_State* state, int index) {
25+
return lua_tostring(state, index);
26+
}
27+
28+
int (lua_isfunction)(lua_State* state, int index) {
29+
return lua_isfunction(state, index);
30+
}
31+
32+
int (lua_istable)(lua_State* state, int index) {
33+
return lua_istable(state, index);
34+
}
35+
36+
int (lua_islightuserdata)(lua_State* state, int index) {
37+
return lua_islightuserdata(state, index);
38+
}
39+
40+
int (lua_isnil)(lua_State* state, int index) {
41+
return lua_isnil(state, index);
42+
}
43+
44+
int (lua_isboolean)(lua_State* state, int index) {
45+
return lua_isboolean(state, index);
46+
}
47+
48+
int (lua_isthread)(lua_State* state, int index) {
49+
return lua_isthread(state, index);
50+
}
51+
52+
int (lua_isnone)(lua_State* state, int index) {
53+
return lua_isnone(state, index);
54+
}
55+
56+
void (lua_insert)(lua_State* state, int index) {
57+
lua_insert(state, index);
58+
}
59+
60+
void (lua_remove)(lua_State* state, int index) {
61+
lua_remove(state, index);
62+
}
63+
64+
void (lua_call)(lua_State* state, int nargs, int nresults) {
65+
lua_call(state, nargs, nresults);
66+
}
67+
68+
int (lua_pcall)(lua_State* state, int nargs, int nresults, int msgh) {
69+
return lua_pcall(state, nargs, nresults, msgh);
70+
}
71+
72+
void (lua_replace)(lua_State* state, int index) {
73+
lua_replace(state, index);
74+
}
75+
76+
int (luaL_loadbuffer)(lua_State* state, char const* buf, size_t size, char const* name) {
77+
return luaL_loadbufferx(state, buf, size, name, NULL);
78+
}

cbits/safe.c

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#include "lua.h"
2+
#include "lauxlib.h"
3+
4+
static int s_newtable(lua_State* state) {
5+
lua_newtable(state);
6+
return 1;
7+
}
8+
9+
int plua_newtable(lua_State* state) {
10+
lua_pushcfunction(state, s_newtable);
11+
return lua_pcall(state, 0, 1, 0);
12+
}
13+
14+
static int s_len(lua_State* state) {
15+
lua_pushinteger(state, luaL_len(state, -1));
16+
return 1;
17+
}
18+
19+
int pluaL_len(lua_State* state, int index, lua_Integer* len) {
20+
index = lua_absindex(state, index);
21+
lua_pushcfunction(state, s_len);
22+
lua_pushvalue(state, index);
23+
int r = lua_pcall(state, 1, 1, 0);
24+
if (r == LUA_OK) {
25+
*len = lua_tointeger(state, -1);
26+
lua_pop(state, 1);
27+
}
28+
return r;
29+
}
30+
31+
static int s_geti(lua_State* state) {
32+
lua_gettable(state, -2);
33+
return 1;
34+
}
35+
36+
int plua_geti(lua_State* state, int index, lua_Integer i) {
37+
index = lua_absindex(state, index);
38+
lua_pushcfunction(state, s_geti);
39+
lua_pushvalue(state, index);
40+
lua_pushinteger(state, i);
41+
return lua_pcall(state, 2, 1, 0);
42+
}
43+
44+
static int s_gettable(lua_State* state) {
45+
lua_gettable(state, -2);
46+
return 1;
47+
}
48+
49+
int plua_gettable(lua_State* state, int index) {
50+
index = lua_absindex(state, index);
51+
lua_pushcfunction(state, s_gettable);
52+
lua_pushvalue(state, index);
53+
lua_rotate(state, -3, -1);
54+
return lua_pcall(state, 2, 1, 0);
55+
}
56+
57+
static int s_newthread(lua_State* state) {
58+
lua_newthread(state);
59+
return 1;
60+
}
61+
62+
int plua_newthread(lua_State* state, lua_State** thread) {
63+
lua_pushcfunction(state, s_newthread);
64+
int r = lua_pcall(state, 0, 1, 0);
65+
if (r == LUA_OK) {
66+
*thread = lua_tothread(state, -1);
67+
}
68+
return r;
69+
}
70+
71+
static int s_newuserdata(lua_State* state) {
72+
size_t size = lua_tointeger(state, -1);
73+
lua_pop(state, 1);
74+
lua_newuserdata(state, size);
75+
return 1;
76+
}
77+
78+
int plua_newuserdata(lua_State* state, size_t size, void** ud) {
79+
lua_pushcfunction(state, s_newuserdata);
80+
lua_pushinteger(state, size);
81+
int r = lua_pcall(state, 1, 1, 0);
82+
if (r == LUA_OK) {
83+
*ud = lua_touserdata(state, -1);
84+
}
85+
return r;
86+
}
87+
88+
static int s_next(lua_State* state) {
89+
if (lua_next(state, -2) == 0) {
90+
return 0;
91+
} else {
92+
return 2;
93+
}
94+
}
95+
96+
int plua_next(lua_State* state, int index, int* res) {
97+
int top = lua_gettop(state) - 1;
98+
index = lua_absindex(state, index);
99+
lua_pushcfunction(state, s_next);
100+
lua_pushvalue(state, index);
101+
lua_rotate(state, -3, -1);
102+
int r = lua_pcall(state, 2, LUA_MULTRET, 0);
103+
if (r == LUA_OK) {
104+
if (lua_gettop(state) - top == 2) {
105+
*res = 1;
106+
} else {
107+
*res = 0;
108+
}
109+
}
110+
return r;
111+
}
112+
113+
static int s_pushcclosure(lua_State* state) {
114+
lua_CFunction cf = lua_tocfunction(state, -1);
115+
lua_pop(state, 1);
116+
lua_pushcclosure(state, cf, lua_gettop(state));
117+
return 1;
118+
}
119+
120+
int plua_pushcclosure(lua_State* state, lua_CFunction function, int n) {
121+
lua_pushcfunction(state, s_pushcclosure);
122+
lua_insert(state, -(n + 1));
123+
lua_pushcfunction(state, function);
124+
return lua_pcall(state, n + 1, 1, 0);
125+
}
126+
127+
static int s_pushlstring(lua_State* state) {
128+
char const* s = lua_touserdata(state, -2);
129+
size_t len = lua_tointeger(state, -1);
130+
lua_pop(state, 2);
131+
lua_pushlstring(state, s, len);
132+
return 1;
133+
}
134+
135+
int plua_pushlstring(lua_State* state, char const* s, size_t len) {
136+
lua_pushcfunction(state, s_pushlstring);
137+
lua_pushlightuserdata(state, (void*)s);
138+
lua_pushinteger(state, len);
139+
return lua_pcall(state, 2, 1, 0);
140+
}
141+
142+
static int s_pushstring(lua_State* state) {
143+
char const* s = lua_touserdata(state, -1);
144+
lua_pop(state, 1);
145+
lua_pushstring(state, s);
146+
return 1;
147+
}
148+
149+
int plua_pushstring(lua_State* state, char const* s) {
150+
lua_pushcfunction(state, s_pushstring);
151+
lua_pushlightuserdata(state, (void*)s);
152+
return lua_pcall(state, 1, 1, 0);
153+
}
154+
155+
static int s_rawset(lua_State* state) {
156+
lua_rawset(state, -3);
157+
return 0;
158+
}
159+
160+
int plua_rawset(lua_State* state, int index) {
161+
lua_pushvalue(state, index);
162+
lua_insert(state, -3);
163+
lua_pushcfunction(state, s_rawset);
164+
lua_insert(state, -4);
165+
return lua_pcall(state, 3, 0, 0);
166+
}
167+
168+
static int s_settable(lua_State* state) {
169+
lua_settable(state, -3);
170+
return 0;
171+
}
172+
173+
int plua_settable(lua_State* state, int index) {
174+
lua_pushvalue(state, index);
175+
lua_insert(state, -3);
176+
lua_pushcfunction(state, s_settable);
177+
lua_insert(state, -4);
178+
return lua_pcall(state, 3, 0, 0);
179+
}
180+
181+
static int s_tostring(lua_State* state) {
182+
char const** s = lua_touserdata(state, -1);
183+
*s = lua_tostring(state, -2);
184+
lua_pop(state, 1);
185+
return 1;
186+
}
187+
188+
int plua_tostring(lua_State* state, int index, char const** s) {
189+
index = lua_absindex(state, index);
190+
lua_pushcfunction(state, s_tostring);
191+
lua_pushvalue(state, index);
192+
lua_pushlightuserdata(state, s);
193+
int r = lua_pcall(state, 2, 1, 0);
194+
if (r == LUA_OK) {
195+
lua_replace(state, index);
196+
}
197+
return r;
198+
}
199+
200+
typedef int (*RustCallback)(lua_State*);
201+
// Out of stack space in callback
202+
static int const RCALL_STACK_ERR = -2;
203+
// Throw the error at the top of the stack
204+
static int const RCALL_ERR = -3;
205+
206+
static int s_call_rust(lua_State* state) {
207+
RustCallback callback = lua_touserdata(state, lua_upvalueindex(1));
208+
int ret = callback(state);
209+
210+
if (ret == LUA_MULTRET) {
211+
return LUA_MULTRET;
212+
} else if (ret == RCALL_STACK_ERR) {
213+
return luaL_error(state, "stack overflow in rust callback");
214+
} else if (ret == RCALL_ERR) {
215+
return lua_error(state);
216+
} else {
217+
return ret;
218+
}
219+
}
220+
221+
int plua_pushrclosure(lua_State* state, RustCallback function, int n) {
222+
lua_pushlightuserdata(state, function);
223+
lua_insert(state, -(n + 1));
224+
return plua_pushcclosure(state, s_call_rust, n + 1);
225+
}

0 commit comments

Comments
 (0)