mirror of
				https://github.com/python/cpython.git
				synced 2025-11-01 06:01:29 +00:00 
			
		
		
		
	GH-93252: Fix error handling for failed Python calls (GH-94693)
This commit is contained in:
		
							parent
							
								
									4bed0db7c2
								
							
						
					
					
						commit
						8a285df806
					
				
					 3 changed files with 19 additions and 1 deletions
				
			
		|  | @ -26,6 +26,18 @@ def fn(**kw): | |||
|         self.assertIsInstance(res, dict) | ||||
|         self.assertEqual(list(res.items()), expected) | ||||
| 
 | ||||
|     def test_frames_are_popped_after_failed_calls(self): | ||||
|         # GH-93252: stuff blows up if we don't pop the new frame after | ||||
|         # recovering from failed calls: | ||||
|         def f(): | ||||
|             pass | ||||
|         for _ in range(1000): | ||||
|             try: | ||||
|                 f(None) | ||||
|             except TypeError: | ||||
|                 pass | ||||
|         # BOOM! | ||||
| 
 | ||||
| 
 | ||||
| @cpython_only | ||||
| class CFunctionCallsErrorMessages(unittest.TestCase): | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| Fix an issue that caused internal frames to outlive failed Python function | ||||
| calls, possibly resulting in memory leaks or hard interpreter crashes. | ||||
|  | @ -6410,7 +6410,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, | |||
|     } | ||||
|     if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) { | ||||
|         assert(frame->owner != FRAME_OWNED_BY_GENERATOR); | ||||
|         _PyFrame_Clear(frame); | ||||
|         _PyEvalFrameClearAndPop(tstate, frame); | ||||
|         return NULL; | ||||
|     } | ||||
|     return frame; | ||||
|  | @ -6432,6 +6432,10 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, | |||
| static void | ||||
| _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame) | ||||
| { | ||||
|     // Make sure that this is, indeed, the top frame. We can't check this in
 | ||||
|     // _PyThreadState_PopFrame, since f_code is already cleared at that point:
 | ||||
|     assert((PyObject **)frame + frame->f_code->co_framesize == | ||||
|            tstate->datastack_top); | ||||
|     tstate->recursion_remaining--; | ||||
|     assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); | ||||
|     assert(frame->owner == FRAME_OWNED_BY_THREAD); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Brandt Bucher
						Brandt Bucher