Skip to content

Commit e56f1bb

Browse files
committed
fix xpcall
1 parent 821a8f2 commit e56f1bb

File tree

1 file changed

+28
-40
lines changed

1 file changed

+28
-40
lines changed

crates/luars/src/lua_vm/mod.rs

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,33 +2020,10 @@ impl LuaVM {
20202020
/// Set runtime error and return lightweight error enum
20212021
/// If an error handler is set (via xpcall), it will be called immediately
20222022
pub fn error(&mut self, message: impl Into<String>) -> LuaError {
2023-
let msg = message.into();
2024-
2025-
// Check if there's an error handler (set by xpcall)
2026-
if let Some(handler) = self.error_handler.clone() {
2027-
// Call the error handler with the error message
2028-
// Note: The call stack is still intact at this point
2029-
let err_value = self.create_string(&msg);
2030-
2031-
match self.call_function_internal(handler, vec![err_value]) {
2032-
Ok(handler_results) => {
2033-
// Error handler succeeded, use its return value as the new error message
2034-
if let Some(result) = handler_results.first() {
2035-
self.error_message = self.value_to_string_raw(result);
2036-
} else {
2037-
self.error_message = msg;
2038-
}
2039-
}
2040-
Err(_) => {
2041-
// Error handler itself failed, use original message
2042-
self.error_message = format!("error in error handler: {}", msg);
2043-
}
2044-
}
2045-
} else {
2046-
// No error handler, just set the message
2047-
self.error_message = msg;
2048-
}
2049-
2023+
// Simply set the error message - error handling is done by xpcall
2024+
// when the error propagates back through the Rust call stack.
2025+
// At that point, the Lua call stack is still intact.
2026+
self.error_message = message.into();
20502027
LuaError::RuntimeError
20512028
}
20522029

@@ -2450,33 +2427,44 @@ impl LuaVM {
24502427
args: Vec<LuaValue>,
24512428
err_handler: LuaValue,
24522429
) -> LuaResult<(bool, Vec<LuaValue>)> {
2453-
// Save old error handler and set the new one
2454-
let old_handler = self.error_handler.clone();
2455-
self.error_handler = Some(err_handler.clone());
2456-
24572430
let initial_frame_count = self.frame_count;
24582431

2459-
// Call the function - if it errors, error() will call the handler
2432+
// Call the function
24602433
let result = self.call_function_internal(func, args);
24612434

2462-
// Restore old error handler
2463-
self.error_handler = old_handler;
2464-
24652435
match result {
24662436
Ok(values) => Ok((true, values)),
24672437
Err(LuaError::Yield) => Err(LuaError::Yield),
24682438
Err(_) => {
2469-
// Error occurred (and handler was already called in error())
2470-
// Clean up frames created by the failed function call
2439+
// Error occurred - call the error handler NOW while the stack is still intact
2440+
// This allows debug.traceback() to see the full call stack
2441+
let error_msg = self.error_message.clone();
2442+
let err_value = self.create_string(&error_msg);
2443+
2444+
let handled_msg = match self.call_function_internal(err_handler, vec![err_value]) {
2445+
Ok(handler_results) => {
2446+
// Error handler succeeded, use its return value as the error message
2447+
if let Some(result) = handler_results.first() {
2448+
self.value_to_string_raw(result)
2449+
} else {
2450+
error_msg
2451+
}
2452+
}
2453+
Err(_) => {
2454+
// Error handler itself failed
2455+
format!("error in error handling: {}", error_msg)
2456+
}
2457+
};
2458+
2459+
// NOW clean up frames created by the failed function call
24712460
while self.frame_count > initial_frame_count {
24722461
let frame = self.pop_frame().unwrap();
24732462
// Close upvalues belonging to this frame
24742463
self.close_upvalues_from(frame.base_ptr);
24752464
}
24762465

2477-
// Return the error message (which may have been modified by the handler)
2478-
let msg = self.error_message.clone();
2479-
let err_str = self.create_string(&msg);
2466+
// Return the handled error message
2467+
let err_str = self.create_string(&handled_msg);
24802468
Ok((false, vec![err_str]))
24812469
}
24822470
}

0 commit comments

Comments
 (0)