Skip to content

Commit 55a5d7e

Browse files
committed
Protect Lua(u) during chunk loading if memory limit is enforced
Relates to #488
1 parent af31dbd commit 55a5d7e

File tree

2 files changed

+53
-24
lines changed

2 files changed

+53
-24
lines changed

src/state/raw.rs

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -319,39 +319,58 @@ impl RawLua {
319319
let state = self.state();
320320
unsafe {
321321
let _sg = StackGuard::new(state);
322-
check_stack(state, 2)?;
322+
check_stack(state, 3)?;
323323

324-
let mode_str = match mode {
324+
let name = name.map(CStr::as_ptr).unwrap_or(ptr::null());
325+
let mode = match mode {
325326
Some(ChunkMode::Binary) => cstr!("b"),
326327
Some(ChunkMode::Text) => cstr!("t"),
327328
None => cstr!("bt"),
328329
};
330+
let status = if cfg!(not(feature = "luau")) || self.unlikely_memory_error() {
331+
self.load_chunk_inner(state, name, env, mode, source)
332+
} else {
333+
// Only Luau can trigger an exception during chunk loading
334+
protect_lua!(state, 0, 1, |state| {
335+
self.load_chunk_inner(state, name, env, mode, source)
336+
})?
337+
};
338+
match status {
339+
ffi::LUA_OK => Ok(Function(self.pop_ref())),
340+
err => Err(pop_error(state, err)),
341+
}
342+
}
343+
}
329344

330-
match ffi::luaL_loadbufferenv(
331-
state,
332-
source.as_ptr() as *const c_char,
333-
source.len(),
334-
name.map(|n| n.as_ptr()).unwrap_or_else(ptr::null),
335-
mode_str,
336-
match env {
337-
Some(env) => {
338-
self.push_ref(&env.0);
339-
-1
340-
}
341-
_ => 0,
342-
},
343-
) {
344-
ffi::LUA_OK => {
345-
#[cfg(feature = "luau-jit")]
346-
if (*self.extra.get()).enable_jit && ffi::luau_codegen_supported() != 0 {
347-
ffi::luau_codegen_compile(state, -1);
348-
}
349-
350-
Ok(Function(self.pop_ref()))
345+
pub(crate) unsafe fn load_chunk_inner(
346+
&self,
347+
state: *mut ffi::lua_State,
348+
name: *const c_char,
349+
env: Option<&Table>,
350+
mode: *const c_char,
351+
source: &[u8],
352+
) -> c_int {
353+
let status = ffi::luaL_loadbufferenv(
354+
state,
355+
source.as_ptr() as *const c_char,
356+
source.len(),
357+
name,
358+
mode,
359+
match env {
360+
Some(env) => {
361+
self.push_ref(&env.0);
362+
-1
351363
}
352-
err => Err(pop_error(state, err)),
364+
_ => 0,
365+
},
366+
);
367+
#[cfg(feature = "luau-jit")]
368+
if status == ffi::LUA_OK {
369+
if (*self.extra.get()).enable_jit && ffi::luau_codegen_supported() != 0 {
370+
ffi::luau_codegen_compile(state, -1);
353371
}
354372
}
373+
status
355374
}
356375

357376
/// Sets a 'hook' function for a thread (coroutine).

tests/memory.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ fn test_memory_limit() -> Result<()> {
3131
lua.set_memory_limit(0)?;
3232
f.call::<()>(()).expect("should trigger no memory limit");
3333

34+
// Test memory limit during chunk loading
35+
lua.set_memory_limit(1024)?;
36+
match lua
37+
.load("local t = {}; for i = 1,10000 do t[i] = i end")
38+
.into_function()
39+
{
40+
Err(Error::MemoryError(_)) => {}
41+
_ => panic!("did not trigger memory error"),
42+
};
43+
3444
Ok(())
3545
}
3646

0 commit comments

Comments
 (0)