mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	gh-118272: Clear generator frame's locals when the generator is closed (#118277)
Co-authored-by: Thomas Grainger <tagrain@gmail.com>
This commit is contained in:
		
							parent
							
								
									f7747f73a9
								
							
						
					
					
						commit
						1f16b4ce56
					
				
					 5 changed files with 38 additions and 5 deletions
				
			
		|  | @ -227,6 +227,9 @@ _PyFrame_GetFrameObject(_PyInterpreterFrame *frame) | ||||||
|     return _PyFrame_MakeAndSetFrameObject(frame); |     return _PyFrame_MakeAndSetFrameObject(frame); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void | ||||||
|  | _PyFrame_ClearLocals(_PyInterpreterFrame *frame); | ||||||
|  | 
 | ||||||
| /* Clears all references in the frame.
 | /* Clears all references in the frame.
 | ||||||
|  * If take is non-zero, then the _PyInterpreterFrame frame |  * If take is non-zero, then the _PyInterpreterFrame frame | ||||||
|  * may be transferred to the frame object it references |  * may be transferred to the frame object it references | ||||||
|  |  | ||||||
|  | @ -532,6 +532,26 @@ def f(): | ||||||
|         with self.assertRaises(RuntimeError): |         with self.assertRaises(RuntimeError): | ||||||
|             gen.close() |             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): | class GeneratorThrowTest(unittest.TestCase): | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | Fix bug where ``generator.close`` does not free the generator frame's | ||||||
|  | locals. | ||||||
|  | @ -380,6 +380,7 @@ gen_close(PyGenObject *gen, PyObject *args) | ||||||
|             // RESUME after YIELD_VALUE and exception depth is 1
 |             // RESUME after YIELD_VALUE and exception depth is 1
 | ||||||
|             assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START); |             assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START); | ||||||
|             gen->gi_frame_state = FRAME_COMPLETED; |             gen->gi_frame_state = FRAME_COMPLETED; | ||||||
|  |             _PyFrame_ClearLocals((_PyInterpreterFrame *)gen->gi_iframe); | ||||||
|             Py_RETURN_NONE; |             Py_RETURN_NONE; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -94,6 +94,17 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 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 | void | ||||||
| _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) | _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) | ||||||
| { | { | ||||||
|  | @ -114,11 +125,7 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) | ||||||
|         } |         } | ||||||
|         Py_DECREF(f); |         Py_DECREF(f); | ||||||
|     } |     } | ||||||
|     assert(frame->stacktop >= 0); |     _PyFrame_ClearLocals(frame); | ||||||
|     for (int i = 0; i < frame->stacktop; i++) { |  | ||||||
|         Py_XDECREF(frame->localsplus[i]); |  | ||||||
|     } |  | ||||||
|     Py_XDECREF(frame->f_locals); |  | ||||||
|     Py_DECREF(frame->f_funcobj); |     Py_DECREF(frame->f_funcobj); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Irit Katriel
						Irit Katriel