bpo-45786: Allocate space for frame in frame object. (GH-29729)

This commit is contained in:
Mark Shannon 2021-11-29 12:34:59 +00:00 committed by GitHub
parent 7431448b81
commit 60929576e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 76 additions and 181 deletions

View file

@ -5694,7 +5694,8 @@ make_coro_frame(PyThreadState *tstate,
}
assert(frame->frame_obj == NULL);
if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) {
_PyFrame_Clear(frame, 1);
_PyFrame_Clear(frame);
PyMem_Free(frame);
return NULL;
}
return frame;
@ -5750,7 +5751,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
localsarray[i] = NULL;
}
if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) {
_PyFrame_Clear(frame, 0);
_PyFrame_Clear(frame);
return NULL;
}
return frame;
@ -5773,11 +5774,8 @@ static int
_PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame)
{
--tstate->recursion_remaining;
assert(frame->frame_obj == NULL || frame->frame_obj->f_own_locals_memory == 0);
if (_PyFrame_Clear(frame, 0)) {
++tstate->recursion_remaining;
return -1;
}
assert(frame->frame_obj == NULL || frame->frame_obj->f_owns_frame == 0);
_PyFrame_Clear(frame);
++tstate->recursion_remaining;
_PyThreadState_PopFrame(tstate, frame);
return 0;

View file

@ -27,22 +27,24 @@ _PyFrame_MakeAndSetFrameObject(InterpreterFrame *frame)
assert(frame->frame_obj == NULL);
PyObject *error_type, *error_value, *error_traceback;
PyErr_Fetch(&error_type, &error_value, &error_traceback);
PyFrameObject *f = _PyFrame_New_NoTrack(frame, 0);
PyFrameObject *f = _PyFrame_New_NoTrack(frame->f_code);
if (f == NULL) {
Py_XDECREF(error_type);
Py_XDECREF(error_value);
Py_XDECREF(error_traceback);
}
else {
f->f_owns_frame = 0;
f->f_frame = frame;
frame->frame_obj = f;
PyErr_Restore(error_type, error_value, error_traceback);
}
frame->frame_obj = f;
return f;
}
static InterpreterFrame *
copy_frame_to_heap(InterpreterFrame *frame)
InterpreterFrame *
_PyFrame_Copy(InterpreterFrame *frame)
{
assert(frame->stacktop >= frame->f_code->co_nlocalsplus);
Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
@ -68,10 +70,11 @@ clear_specials(InterpreterFrame *frame)
static void
take_ownership(PyFrameObject *f, InterpreterFrame *frame)
{
assert(f->f_own_locals_memory == 0);
assert(frame->frame_obj == NULL);
f->f_own_locals_memory = 1;
assert(f->f_owns_frame == 0);
Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
memcpy((InterpreterFrame *)f->_f_frame_data, frame, size);
frame = (InterpreterFrame *)f->_f_frame_data;
f->f_owns_frame = 1;
f->f_frame = frame;
assert(f->f_back == NULL);
if (frame->previous != NULL) {
@ -82,7 +85,6 @@ take_ownership(PyFrameObject *f, InterpreterFrame *frame)
assert(PyErr_ExceptionMatches(PyExc_MemoryError));
/* Nothing we can do about it */
PyErr_Clear();
_PyErr_WriteUnraisableMsg("Out of memory lazily allocating frame->f_back", NULL);
}
else {
f->f_back = (PyFrameObject *)Py_NewRef(back);
@ -94,8 +96,8 @@ take_ownership(PyFrameObject *f, InterpreterFrame *frame)
}
}
int
_PyFrame_Clear(InterpreterFrame * frame, int take)
void
_PyFrame_Clear(InterpreterFrame * frame)
{
/* It is the responsibility of the owning generator/coroutine
* to have cleared the generator pointer */
@ -104,15 +106,9 @@ _PyFrame_Clear(InterpreterFrame * frame, int take)
PyFrameObject *f = frame->frame_obj;
frame->frame_obj = NULL;
if (Py_REFCNT(f) > 1) {
if (!take) {
frame = copy_frame_to_heap(frame);
if (frame == NULL) {
return -1;
}
}
take_ownership(f, frame);
Py_DECREF(f);
return 0;
return;
}
Py_DECREF(f);
}
@ -121,8 +117,4 @@ _PyFrame_Clear(InterpreterFrame * frame, int take)
Py_XDECREF(frame->localsplus[i]);
}
clear_specials(frame);
if (take) {
PyMem_Free(frame);
}
return 0;
}