diff --git a/crates/vm/src/frame.rs b/crates/vm/src/frame.rs index c1d7d4e14..55ba720a5 100644 --- a/crates/vm/src/frame.rs +++ b/crates/vm/src/frame.rs @@ -4171,6 +4171,7 @@ impl ExecutingFrame<'_> { Ok(None) => next_idx = lasti_cell.load(Relaxed), Ok(Some(result)) => break Ok(Some(result)), Err(exception) => { + monitoring::reset_reraise_pending(); // Fire PY_UNWIND: exception escapes this frame let exception = if vm.state.monitoring_events.load() & MonitoringEvent::PyUnwind.mask() @@ -4454,6 +4455,7 @@ impl ExecutingFrame<'_> { } Ok(Some(result)) => Ok(result), Err(exception) => { + monitoring::reset_reraise_pending(); // Fire PY_UNWIND: exception escapes the generator frame. let exception = if vm.state.monitoring_events.load() & MonitoringEvent::PyUnwind.mask() != 0 { @@ -8922,6 +8924,7 @@ impl ExecutingFrame<'_> { if let Some(entry) = bytecode::find_exception_handler(&self.code.exceptiontable, offset) { + monitoring::reset_reraise_pending(); // Fire EXCEPTION_HANDLED before setting up handler. // If the callback raises, the handler is NOT set up and the // new exception propagates instead. diff --git a/crates/vm/src/stdlib/sys/monitoring.rs b/crates/vm/src/stdlib/sys/monitoring.rs index 5076e8a97..7d1aa61d5 100644 --- a/crates/vm/src/stdlib/sys/monitoring.rs +++ b/crates/vm/src/stdlib/sys/monitoring.rs @@ -1083,6 +1083,12 @@ pub(crate) fn fire_raise( ) } +/// End suppression when the exception reaches a handler or escapes a frame, +/// independently of whether either lifecycle event has a registered callback. +pub(crate) fn reset_reraise_pending() { + RERAISE_PENDING.with(|f| f.set(false)); +} + /// Only fires if no RERAISE has been fired since the last EXCEPTION_HANDLED, /// preventing duplicate events from chained cleanup handlers. pub(crate) fn fire_reraise( @@ -1114,7 +1120,7 @@ pub(crate) fn fire_exception_handled( offset: u32, exception: &PyObject, ) -> PyResult<()> { - RERAISE_PENDING.with(|f| f.set(false)); + reset_reraise_pending(); fire( vm, MonitoringEvent::ExceptionHandled, @@ -1130,7 +1136,7 @@ pub(crate) fn fire_py_unwind( offset: u32, exception: &PyObject, ) -> PyResult<()> { - RERAISE_PENDING.with(|f| f.set(false)); + reset_reraise_pending(); fire( vm, MonitoringEvent::PyUnwind,