@@ -1802,8 +1802,24 @@ impl LuaVM {
18021802 let code_ptr = func_ref. chunk . code . as_ptr ( ) ;
18031803 let constants_ptr = func_ref. chunk . constants . as_ptr ( ) ;
18041804
1805- // Allocate registers in global stack
1806- let new_base = self . register_stack . len ( ) ;
1805+ // CRITICAL FIX: Calculate new base relative to current frame
1806+ // This prevents register_stack from growing indefinitely
1807+ let new_base = if self . frame_count > 0 {
1808+ let current_frame = & self . frames [ self . frame_count - 1 ] ;
1809+ let caller_base = current_frame. base_ptr ;
1810+ let caller_max_stack =
1811+ if let Some ( caller_func_id) = current_frame. function_value . as_function_id ( ) {
1812+ self . object_pool
1813+ . get_function ( caller_func_id)
1814+ . map ( |f| f. chunk . max_stack_size )
1815+ . unwrap_or ( 256 )
1816+ } else {
1817+ 256
1818+ } ;
1819+ caller_base + caller_max_stack
1820+ } else {
1821+ 0
1822+ } ;
18071823 self . ensure_stack_capacity ( new_base + max_stack_size) ;
18081824
18091825 // Copy arguments to new frame's registers
@@ -1841,7 +1857,24 @@ impl LuaVM {
18411857 let cf = metamethod. as_cfunction ( ) . unwrap ( ) ;
18421858 // Create temporary frame for CFunction
18431859 let arg_count = args. len ( ) + 1 ; // +1 for function itself
1844- let new_base = self . register_stack . len ( ) ;
1860+
1861+ // CRITICAL FIX: Calculate new base relative to current frame
1862+ let new_base = if self . frame_count > 0 {
1863+ let current_frame = & self . frames [ self . frame_count - 1 ] ;
1864+ let caller_base = current_frame. base_ptr ;
1865+ let caller_max_stack =
1866+ if let Some ( caller_func_id) = current_frame. function_value . as_function_id ( ) {
1867+ self . object_pool
1868+ . get_function ( caller_func_id)
1869+ . map ( |f| f. chunk . max_stack_size )
1870+ . unwrap_or ( 256 )
1871+ } else {
1872+ 256
1873+ } ;
1874+ caller_base + caller_max_stack
1875+ } else {
1876+ 0
1877+ } ;
18451878 self . ensure_stack_capacity ( new_base + arg_count) ;
18461879
18471880 self . register_stack [ new_base] = LuaValue :: cfunction ( cf) ;
@@ -2196,15 +2229,29 @@ impl LuaVM {
21962229 // Normal return - pop boundary frame and get return values
21972230 self . pop_frame_discard ( ) ;
21982231 let result = std:: mem:: take ( & mut self . return_values ) ;
2232+
2233+ // Clear the stack region used by this call to release references
2234+ // This prevents GC from scanning stale objects after dofile/pcall
2235+ for i in new_base..( new_base + max_stack_size) {
2236+ if i < self . register_stack . len ( ) {
2237+ self . register_stack [ i] = LuaValue :: nil ( ) ;
2238+ }
2239+ }
2240+
21992241 Ok ( result)
22002242 }
22012243 Err ( LuaError :: Yield ) => {
22022244 // Yield - frames stay for resume
22032245 Err ( LuaError :: Yield )
22042246 }
22052247 Err ( e) => {
2206- // Error - pop boundary frame
2248+ // Error - pop boundary frame and clear stack region
22072249 self . pop_frame_discard ( ) ;
2250+ for i in new_base..( new_base + max_stack_size) {
2251+ if i < self . register_stack . len ( ) {
2252+ self . register_stack [ i] = LuaValue :: nil ( ) ;
2253+ }
2254+ }
22082255 Err ( e)
22092256 }
22102257 }
0 commit comments