(
frame: &mut ExecutingFrame<'_>,
exception: PyBaseExceptionRef,
idx: usize,
is_reraise: bool,
| 1556 | Err(exception) => { |
| 1557 | #[cold] |
| 1558 | fn handle_exception( |
| 1559 | frame: &mut ExecutingFrame<'_>, |
| 1560 | exception: PyBaseExceptionRef, |
| 1561 | idx: usize, |
| 1562 | is_reraise: bool, |
| 1563 | is_new_raise: bool, |
| 1564 | vm: &VirtualMachine, |
| 1565 | ) -> FrameResult { |
| 1566 | // 1. Extract traceback from exception's '__traceback__' attr. |
| 1567 | // 2. Add new entry with current execution position (filename, lineno, code_object) to traceback. |
| 1568 | // 3. First, try to find handler in exception table |
| 1569 | |
| 1570 | // RERAISE instructions should not add traceback entries - they're just |
| 1571 | // re-raising an already-processed exception |
| 1572 | if !is_reraise { |
| 1573 | // Check if the exception already has traceback entries before |
| 1574 | // we add ours. If it does, it was propagated from a callee |
| 1575 | // function and we should not re-contextualize it. |
| 1576 | let had_prior_traceback = exception.__traceback__().is_some(); |
| 1577 | |
| 1578 | // PyTraceBack_Here always adds a new entry without |
| 1579 | // checking for duplicates. Each time an exception passes through |
| 1580 | // a frame (e.g., in a loop with repeated raise statements), |
| 1581 | // a new traceback entry is added. |
| 1582 | let (loc, _end_loc) = frame.code.locations[idx]; |
| 1583 | let next = exception.__traceback__(); |
| 1584 | |
| 1585 | let new_traceback = PyTraceback::new( |
| 1586 | next, |
| 1587 | frame.object.to_owned(), |
| 1588 | idx as u32 * 2, |
| 1589 | loc.line, |
| 1590 | ); |
| 1591 | vm_trace!("Adding to traceback: {:?} {:?}", new_traceback, loc.line); |
| 1592 | exception.set_traceback_typed(Some(new_traceback.into_ref(&vm.ctx))); |
| 1593 | |
| 1594 | // _PyErr_SetObject sets __context__ only when the exception |
| 1595 | // is first raised. When an exception propagates through frames, |
| 1596 | // __context__ must not be overwritten. We contextualize when: |
| 1597 | // - It's an explicit raise (raise/raise from) |
| 1598 | // - The exception had no prior traceback (originated here) |
| 1599 | if is_new_raise || !had_prior_traceback { |
| 1600 | vm.contextualize_exception(&exception); |
| 1601 | } |
| 1602 | } |
| 1603 | |
| 1604 | // Use exception table for zero-cost exception handling |
| 1605 | frame.unwind_blocks(vm, UnwindReason::Raising { exception }) |
| 1606 | } |
| 1607 | |
| 1608 | // Check if this is a RERAISE instruction |
| 1609 | // Both AnyInstruction::Raise { kind: Reraise/ReraiseFromStack } and |
nothing calls this directly
no test coverage detected