gh-118272: Clear generator frame's locals when the generator is close… · python/cpython@1f16b4c

GitHub

File tree

Include/internal

Lib/test

Misc/NEWS.d/next/Core and Builtins

Objects

Python

Original file line numberDiff line numberDiff line change@@ -227,6 +227,9 @@ _PyFrame_GetFrameObject(_PyInterpreterFrame *frame)

227227return_PyFrame_MakeAndSetFrameObject(frame);

228228}

229229230+void

231+_PyFrame_ClearLocals(_PyInterpreterFrame*frame);

232+230233/* Clears all references in the frame.

231234 * If take is non-zero, then the _PyInterpreterFrame frame

232235 * may be transferred to the frame object it references

Original file line numberDiff line numberDiff line change@@ -532,6 +532,26 @@ def f():

532532withself.assertRaises(RuntimeError):

533533gen.close()

534534535+deftest_close_releases_frame_locals(self):

536+# See gh-118272

537+538+classFoo:

539+pass

540+541+f=Foo()

542+f_wr=weakref.ref(f)

543+544+defgenfn():

545+a=f

546+yield

547+548+g=genfn()

549+next(g)

550+delf

551+g.close()

552+support.gc_collect()

553+self.assertIsNone(f_wr())

554+535555536556classGeneratorThrowTest(unittest.TestCase):

537557Original file line numberDiff line numberDiff line change@@ -0,0 +1,2 @@

1+Fix bug where ``generator.close`` does not free the generator frame's

2+locals.

Original file line numberDiff line numberDiff line change@@ -380,6 +380,7 @@ gen_close(PyGenObject *gen, PyObject *args)

380380// RESUME after YIELD_VALUE and exception depth is 1

381381assert((oparg&RESUME_OPARG_LOCATION_MASK) !=RESUME_AT_FUNC_START);

382382gen->gi_frame_state=FRAME_COMPLETED;

383+_PyFrame_ClearLocals((_PyInterpreterFrame*)gen->gi_iframe);

383384Py_RETURN_NONE;

384385 }

385386 }

Original file line numberDiff line numberDiff line change@@ -94,6 +94,17 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)

9494 }

9595}

969697+void

98+_PyFrame_ClearLocals(_PyInterpreterFrame*frame)

99+{

100+assert(frame->stacktop >= 0);

101+for (inti=0; i<frame->stacktop; i++) {

102+Py_XDECREF(frame->localsplus[i]);

103+ }

104+frame->stacktop=0;

105+Py_CLEAR(frame->f_locals);

106+}

107+97108void

98109_PyFrame_ClearExceptCode(_PyInterpreterFrame*frame)

99110{

@@ -114,11 +125,7 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)

114125 }

115126Py_DECREF(f);

116127 }

117-assert(frame->stacktop >= 0);

118-for (inti=0; i<frame->stacktop; i++) {

119-Py_XDECREF(frame->localsplus[i]);

120- }

121-Py_XDECREF(frame->f_locals);

128+_PyFrame_ClearLocals(frame);

122129Py_DECREF(frame->f_funcobj);

123130}

124131