PyAPI_FUNC(PyObject *)_PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type, Py_ssize_t nargs, PyObject *kwargs);
PyAPI_FUNC(PyObject *)_PyEval_MatchKeys(PyThreadState *tstate, PyObject *map, PyObject *keys);
PyAPI_FUNC(void) _PyEval_MonitorRaise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr);
+PyAPI_FUNC(bool) _PyEval_NoToolsForUnwind(PyThreadState *tstate);
PyAPI_FUNC(int) _PyEval_UnpackIterableStackRef(PyThreadState *tstate, PyObject *v, int argcnt, int argcntafter, _PyStackRef *sp);
PyAPI_FUNC(void) _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);
PyAPI_FUNC(PyObject **) _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_ssize_t nargs, PyObject **scratch);
self.assertEqual(events, expected)
+ # gh-140373
+ def test_gen_unwind(self):
+ def gen():
+ yield 1
+
+ def f():
+ g = gen()
+ next(g)
+ g.close()
+
+ recorders = (
+ UnwindRecorder,
+ )
+ events = self.get_events(f, TEST_TOOL, recorders)
+ expected = [
+ ("unwind", GeneratorExit, "gen"),
+ ]
+ self.assertEqual(events, expected)
+
class LineRecorder:
event_type = E.LINE
self.check_events(g, [(1, 'call', g_ident, None),
(2, 'call', f_ident, None),
(2, 'return', f_ident, 0),
+ (2, 'call', f_ident, None),
+ (2, 'return', f_ident, None),
(1, 'return', g_ident, None),
], check_args=True)
--- /dev/null
+Correctly emit ``PY_UNWIND`` event when generator object is closed. Patch by
+Mikhail Efimov.
}
_PyInterpreterFrame *frame = &gen->gi_iframe;
if (is_resume(frame->instr_ptr)) {
+ bool no_unwind_tools = _PyEval_NoToolsForUnwind(_PyThreadState_GET());
/* We can safely ignore the outermost try block
* as it is automatically generated to handle
* StopIteration. */
int oparg = frame->instr_ptr->op.arg;
- if (oparg & RESUME_OPARG_DEPTH1_MASK) {
+ if (oparg & RESUME_OPARG_DEPTH1_MASK && no_unwind_tools) {
// RESUME after YIELD_VALUE and exception depth is 1
assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START);
gen->gi_frame_state = FRAME_COMPLETED;
do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_UNWIND);
}
+bool
+_PyEval_NoToolsForUnwind(PyThreadState *tstate) {
+ return no_tools_for_global_event(tstate, PY_MONITORING_EVENT_PY_UNWIND);
+}
static int
monitor_handled(PyThreadState *tstate,