Skip to main content

luaur_vm/functions/
lua_m_realloc.rs

1//! Node: `cxx:Function:Luau.VM:VM/src/lmem.cpp:599:luaM_realloc_`
2//! Source: `VM/src/lmem.cpp:599-640` (hand-fixed: the translated version
3//! invented a power-of-2 size-class scheme that disagreed with the real
4//! progressive table in `sizeclass!`, so realloc'd blocks were freed under
5//! the wrong class and tripped the blockSize assert in `freeblock`)
6
7use crate::enums::lua_status::lua_Status;
8use crate::functions::freeblock::freeblock;
9use crate::functions::lua_d_throw_ldo::lua_d_throw;
10use crate::functions::newblock::newblock;
11use crate::macros::sizeclass::sizeclass;
12use crate::type_aliases::lua_state::lua_State;
13use core::ffi::c_void;
14use luaur_common::macros::luau_assert::LUAU_ASSERT;
15use luaur_common::macros::luau_unlikely::LUAU_UNLIKELY;
16
17#[allow(non_snake_case)]
18pub unsafe fn lua_m_realloc_(
19    l: *mut lua_State,
20    block: *mut c_void,
21    osize: usize,
22    nsize: usize,
23    memcat: u8,
24) -> *mut c_void {
25    let g = (*l).global;
26    LUAU_ASSERT!((osize == 0) == (block.is_null()));
27
28    let nclass = sizeclass!(nsize) as i32;
29    let oclass = sizeclass!(osize) as i32;
30    let result: *mut c_void;
31
32    // if either block needs to be allocated using a block allocator, we can't use realloc directly
33    if nclass >= 0 || oclass >= 0 {
34        result = if nclass >= 0 {
35            newblock(l, nclass)
36        } else {
37            ((*g).frealloc.expect("frealloc is null"))((*g).ud, core::ptr::null_mut(), 0, nsize)
38        };
39
40        if result.is_null() && nsize > 0 {
41            lua_d_throw(l, lua_Status::LUA_ERRMEM as i32);
42        }
43
44        if osize > 0 && nsize > 0 {
45            let copy_size = if osize < nsize { osize } else { nsize };
46            core::ptr::copy_nonoverlapping(block as *const u8, result as *mut u8, copy_size);
47        }
48
49        if oclass >= 0 {
50            freeblock(l, oclass, block);
51        } else {
52            ((*g).frealloc.expect("frealloc is null"))((*g).ud, block, osize, 0);
53        }
54    } else {
55        result = ((*g).frealloc.expect("frealloc is null"))((*g).ud, block, osize, nsize);
56        if result.is_null() && nsize > 0 {
57            lua_d_throw(l, lua_Status::LUA_ERRMEM as i32);
58        }
59    }
60
61    LUAU_ASSERT!((nsize == 0) == (result.is_null()));
62    (*g).totalbytes = (*g).totalbytes.wrapping_sub(osize).wrapping_add(nsize);
63    (*g).memcatbytes[memcat as usize] = (*g).memcatbytes[memcat as usize]
64        .wrapping_add(nsize)
65        .wrapping_sub(osize);
66
67    if LUAU_UNLIKELY!((*g).cb.onallocate.is_some()) {
68        ((*g).cb.onallocate.unwrap_unchecked())(l, osize, nsize);
69    }
70
71    result
72}