Skip to main content

luaur_code_gen/functions/
execute_setlist.rs

1use luaur_vm::functions::lua_h_resizearray::lua_h_resizearray;
2use luaur_vm::macros::clvalue::clvalue;
3use luaur_vm::macros::hvalue::hvalue;
4use luaur_vm::macros::lua_c_barrierfast::lua_c_barrierfast;
5use luaur_vm::macros::setobj_2_t::setobj2t;
6use luaur_vm::macros::ttistable::ttistable;
7use luaur_vm::type_aliases::t_value::TValue;
8
9use crate::macros::vm_protect_pc::VM_PROTECT_PC;
10use crate::macros::vm_reg::VM_REG;
11use crate::type_aliases::instruction_ir_builder::Instruction;
12use crate::type_aliases::lua_state::lua_State;
13use luaur_vm::type_aliases::stk_id::StkId;
14
15use luaur_common::macros::luau_insn_a::LUAU_INSN_A;
16use luaur_common::macros::luau_insn_b::LUAU_INSN_B;
17use luaur_common::macros::luau_insn_c::LUAU_INSN_C;
18use luaur_vm::macros::lua_multret::LUA_MULTRET;
19
20pub unsafe fn execute_setlist(
21    L: *mut lua_State,
22    pc: *const Instruction,
23    base: StkId,
24    _k: *mut TValue,
25) -> *const Instruction {
26    let l_ptr = L as *mut luaur_vm::records::lua_state::lua_State;
27    let cl = clvalue!((*(*l_ptr).ci).func);
28    let _ = cl; // unused in this function
29
30    let mut pc_ptr = pc;
31    let insn = *pc_ptr;
32    pc_ptr = pc_ptr.add(1);
33
34    let ra = VM_REG!(LUAU_INSN_A(insn) as i32, l_ptr, base);
35    // note: this can point to L->top if c == LUA_MULTRET making VM_REG unsafe to use
36    let rb = base.add(LUAU_INSN_B(insn) as usize);
37    let mut c = (LUAU_INSN_C(insn) as i32) - 1;
38    let index = *pc_ptr;
39    pc_ptr = pc_ptr.add(1);
40
41    if c == LUA_MULTRET {
42        c = (*l_ptr).top.offset_from(rb) as i32;
43        (*l_ptr).top = (*(*l_ptr).ci).top;
44    }
45
46    let h = hvalue!(ra as *const TValue);
47
48    // TODO: we really don't need this anymore
49    if !ttistable!(ra as *const TValue) {
50        return core::ptr::null(); // temporary workaround to weaken a rather powerful exploitation primitive in case of a MITM attack on bytecode
51    }
52
53    let last = index as i32 + c - 1;
54    if last > (*h).sizearray {
55        // VM_PROTECT_PC expects the local crate's lua_State pointer
56        VM_PROTECT_PC(L, pc_ptr as *const u32); // luaH_resizearray may fail due to OOM
57
58        lua_h_resizearray(l_ptr, h, last);
59    }
60
61    let array = (*h).array;
62
63    for i in 0..c {
64        setobj2t!(
65            l_ptr,
66            array.add((index as i32 + i - 1) as usize),
67            rb.add(i as usize)
68        );
69    }
70
71    lua_c_barrierfast!(l_ptr, h);
72    pc_ptr
73}
74
75#[no_mangle]
76pub unsafe extern "C" fn executeSETLIST(
77    L: *mut lua_State,
78    pc: *const Instruction,
79    base: StkId,
80    k: *mut TValue,
81) -> *const Instruction {
82    execute_setlist(L, pc, base, k)
83}