@@ -50,20 +50,19 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
5050{
5151 assert (frame -> owner < FRAME_OWNED_BY_INTERPRETER );
5252 assert (frame -> owner != FRAME_OWNED_BY_FRAME_OBJECT );
53- Py_ssize_t size = ((char * )frame -> stackpointer ) - (char * )frame ;
54- memcpy ((_PyInterpreterFrame * )f -> _f_frame_data , frame , size );
55- frame = (_PyInterpreterFrame * )f -> _f_frame_data ;
56- frame -> stackpointer = (_PyStackRef * )(((char * )frame ) + size );
53+ // While ownership of f_executable is transferred to the frame object, the
54+ // reference in the frame will also be closed when the frame is popped from
55+ // the stack. Create another reference to ensure that works correctly.
56+ //
57+ // This must happen in the source frame (not in the frame
58+ // object). _PyFrame_CopyToHeap converts borrowed references in the source
59+ // frame into strong references in the destination frame. duping the
60+ // reference in the dest frame would result in a leak if the source was
61+ // borrowed because the close on the source would not destroy the newly
62+ // created reference.
5763 frame -> f_executable = PyStackRef_DUP (frame -> f_executable );
58- int stacktop = (int )(frame -> stackpointer - frame -> localsplus );
59- assert (stacktop >= _PyFrame_GetCode (frame )-> co_nlocalsplus );
60- // The frame object may outlive any references that were providing "support"
61- // for borrowed references in the frame. Convert them to strong references.
62- frame -> f_executable = _PyStackRef_NewIfBorrowedOrSteal (frame -> f_executable );
63- frame -> f_funcobj = _PyStackRef_NewIfBorrowedOrSteal (frame -> f_funcobj );
64- for (int i = 0 ; i < stacktop ; i ++ ) {
65- frame -> localsplus [i ] = _PyStackRef_NewIfBorrowedOrSteal (frame -> localsplus [i ]);
66- }
64+ _PyFrame_CopyToHeap (frame , (_PyInterpreterFrame * ) f -> _f_frame_data );
65+ frame = (_PyInterpreterFrame * )f -> _f_frame_data ;
6766 f -> f_frame = frame ;
6867 frame -> owner = FRAME_OWNED_BY_FRAME_OBJECT ;
6968 if (_PyFrame_IsIncomplete (frame )) {
0 commit comments