Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions crates/luaur-rt/src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,24 @@ pub struct Table {
pub(crate) _not_sync: NotSync,
}

/// Reserve `slots` stack slots for a raw table operation.
///
/// `lua_checkstack` raises the stack top inside the current call-info frame;
/// without it, `lua_pushvalue` (and the extra copy `value_from_stack` pushes
/// for reference types) can trip the `top < ci.top` LUAU_ASSERT and abort the
/// process when the caller's stack margin is already thin (for example after
/// a long sequence of VM operations in the same frame).
pub(crate) fn ensure_stack(state: *mut lua_State, slots: c_int) -> Result<()> {
if unsafe { lua_checkstack(state, slots) } == 0 {
// Same shape as the guards in `Function::call` / `Thread::resume`:
// a catchable `RuntimeError` rather than a VM abort.
return Err(crate::error::Error::RuntimeError(
"stack overflow: not enough stack space for a raw table operation".to_string(),
));
}
Ok(())
}

impl Table {
pub(crate) fn from_ref(reference: LuaRef) -> Table {
Table {
Expand Down Expand Up @@ -209,6 +227,7 @@ impl Table {
"attempt to modify a readonly table".to_string(),
));
}
ensure_stack(state, 3)?;
unsafe {
self.reference.push(); // table
lua.push_value(&k)?; // key
Expand All @@ -226,6 +245,7 @@ impl Table {
let lua = self.lua();
let state = lua.state();
let k = key.into_lua(&lua)?;
ensure_stack(state, 3)?;
let value = unsafe {
self.reference.push(); // table
lua.push_value(&k)?; // key
Expand Down
39 changes: 39 additions & 0 deletions crates/luaur-rt/tests/mlua_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1283,3 +1283,42 @@ fn test_inspect_stack_deferred() -> Result<()> {

Ok(())
}

// `raw_set` / `raw_get` reserve their stack slots up front (`lua_checkstack`)
// instead of pushing blind, matching the guards in `Function::call` /
// `Thread::resume`. Coverage for sustained raw traffic interleaved with VM
// work; it does not by itself drive the frame margin low enough to trip the
// VM's `top < ci.top` assertion (a C frame always gets LUA_MINSTACK headroom).
#[test]
fn test_raw_table_ops_reserve_stack_space() -> Result<()> {
let lua = Lua::new();

let table = lua.create_table();
for i in 0..2000i64 {
table.raw_set(format!("k{i}"), i)?;
}
for i in 0..2000i64 {
let v: i64 = table.raw_get(format!("k{i}"))?;
assert_eq!(v, i);
}

// Deep recursion inside the VM, then raw ops from the host right after.
lua.load(
r#"
function deep(n)
if n == 0 then return 0 end
return 1 + deep(n - 1)
end
return deep(150)
"#,
)
.eval::<i64>()?;

for i in 0..500i64 {
table.raw_set(format!("post{i}"), i)?;
let v: i64 = table.raw_get(format!("post{i}"))?;
assert_eq!(v, i);
}

Ok(())
}
2 changes: 2 additions & 0 deletions fuzz/seeds/metamorphic/alias
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type T = {x: number}
local v: T = {x=1}
2 changes: 2 additions & 0 deletions fuzz/seeds/metamorphic/annot
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local x: number = 1
return x
2 changes: 2 additions & 0 deletions fuzz/seeds/metamorphic/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
for i=1,3 do end
while true do break end
1 change: 1 addition & 0 deletions fuzz/seeds/metamorphic/expr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return 1 + 2
1 change: 1 addition & 0 deletions fuzz/seeds/metamorphic/func
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
function f(a: string): number return #a end
2 changes: 2 additions & 0 deletions fuzz/seeds/metamorphic/table
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local t = {a=1, b="s"}
return t.a
2 changes: 2 additions & 0 deletions fuzz/seeds/optdiff/alias
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type T = {x: number}
local v: T = {x=1}
2 changes: 2 additions & 0 deletions fuzz/seeds/optdiff/annot
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local x: number = 1
return x
2 changes: 2 additions & 0 deletions fuzz/seeds/optdiff/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
for i=1,3 do end
while true do break end
1 change: 1 addition & 0 deletions fuzz/seeds/optdiff/expr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return 1 + 2
1 change: 1 addition & 0 deletions fuzz/seeds/optdiff/func
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
function f(a: string): number return #a end
2 changes: 2 additions & 0 deletions fuzz/seeds/optdiff/table
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local t = {a=1, b="s"}
return t.a
2 changes: 2 additions & 0 deletions fuzz/seeds/roundtrip/alias
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type T = {x: number}
local v: T = {x=1}
2 changes: 2 additions & 0 deletions fuzz/seeds/roundtrip/annot
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local x: number = 1
return x
2 changes: 2 additions & 0 deletions fuzz/seeds/roundtrip/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
for i=1,3 do end
while true do break end
1 change: 1 addition & 0 deletions fuzz/seeds/roundtrip/expr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return 1 + 2
1 change: 1 addition & 0 deletions fuzz/seeds/roundtrip/func
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
function f(a: string): number return #a end
2 changes: 2 additions & 0 deletions fuzz/seeds/roundtrip/table
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local t = {a=1, b="s"}
return t.a
2 changes: 2 additions & 0 deletions fuzz/seeds/splice/alias
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type T = {x: number}
local v: T = {x=1}
2 changes: 2 additions & 0 deletions fuzz/seeds/splice/annot
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local x: number = 1
return x
2 changes: 2 additions & 0 deletions fuzz/seeds/splice/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
for i=1,3 do end
while true do break end
1 change: 1 addition & 0 deletions fuzz/seeds/splice/expr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return 1 + 2
1 change: 1 addition & 0 deletions fuzz/seeds/splice/func
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
function f(a: string): number return #a end
2 changes: 2 additions & 0 deletions fuzz/seeds/splice/table
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local t = {a=1, b="s"}
return t.a
2 changes: 2 additions & 0 deletions fuzz/seeds/typeck_typed/alias
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type T = {x: number}
local v: T = {x=1}
2 changes: 2 additions & 0 deletions fuzz/seeds/typeck_typed/annot
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local x: number = 1
return x
2 changes: 2 additions & 0 deletions fuzz/seeds/typeck_typed/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
for i=1,3 do end
while true do break end
1 change: 1 addition & 0 deletions fuzz/seeds/typeck_typed/expr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return 1 + 2
1 change: 1 addition & 0 deletions fuzz/seeds/typeck_typed/func
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
function f(a: string): number return #a end
2 changes: 2 additions & 0 deletions fuzz/seeds/typeck_typed/table
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local t = {a=1, b="s"}
return t.a
Loading