return _PyFrame_MakeAndSetFrameObject(frame);
}
+void
+_PyFrame_ClearLocals(_PyInterpreterFrame *frame);
+
/* Clears all references in the frame.
* If take is non-zero, then the _PyInterpreterFrame frame
* may be transferred to the frame object it references
with self.assertRaises(RuntimeError):
gen.close()
+ def test_close_releases_frame_locals(self):
+ # See gh-118272
+
+ class Foo:
+ pass
+
+ f = Foo()
+ f_wr = weakref.ref(f)
+
+ def genfn():
+ a = f
+ yield
+
+ g = genfn()
+ next(g)
+ del f
+ g.close()
+ support.gc_collect()
+ self.assertIsNone(f_wr())
+
class GeneratorThrowTest(unittest.TestCase):
// 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;
+ _PyFrame_ClearLocals((_PyInterpreterFrame *)gen->gi_iframe);
Py_RETURN_NONE;
}
}
}
}
+void
+_PyFrame_ClearLocals(_PyInterpreterFrame *frame)
+{
+ assert(frame->stacktop >= 0);
+ for (int i = 0; i < frame->stacktop; i++) {
+ Py_XDECREF(frame->localsplus[i]);
+ }
+ frame->stacktop = 0;
+ Py_CLEAR(frame->f_locals);
+}
+
void
_PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
{
}
Py_DECREF(f);
}
- assert(frame->stacktop >= 0);
- for (int i = 0; i < frame->stacktop; i++) {
- Py_XDECREF(frame->localsplus[i]);
- }
- Py_XDECREF(frame->f_locals);
+ _PyFrame_ClearLocals(frame);
Py_DECREF(frame->f_funcobj);
}