mirror of
https://github.com/python/cpython.git
synced 2025-08-30 05:35:08 +00:00
GH-97002: Prevent _PyInterpreterFrame
s from backing more than one PyFrameObject
(GH-97996)
This commit is contained in:
parent
cbf0afd8a1
commit
21a2d9ff55
3 changed files with 91 additions and 6 deletions
|
@ -37,14 +37,31 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
|
|||
Py_XDECREF(error_type);
|
||||
Py_XDECREF(error_value);
|
||||
Py_XDECREF(error_traceback);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
|
||||
assert(frame->owner != FRAME_CLEARED);
|
||||
f->f_frame = frame;
|
||||
frame->frame_obj = f;
|
||||
PyErr_Restore(error_type, error_value, error_traceback);
|
||||
PyErr_Restore(error_type, error_value, error_traceback);
|
||||
if (frame->frame_obj) {
|
||||
// GH-97002: How did we get into this horrible situation? Most likely,
|
||||
// allocating f triggered a GC collection, which ran some code that
|
||||
// *also* created the same frame... while we were in the middle of
|
||||
// creating it! See test_sneaky_frame_object in test_frame.py for a
|
||||
// concrete example.
|
||||
//
|
||||
// Regardless, just throw f away and use that frame instead, since it's
|
||||
// already been exposed to user code. It's actually a bit tricky to do
|
||||
// this, since we aren't backed by a real _PyInterpreterFrame anymore.
|
||||
// Just pretend that we have an owned, cleared frame so frame_dealloc
|
||||
// doesn't make the situation worse:
|
||||
f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data;
|
||||
f->f_frame->owner = FRAME_CLEARED;
|
||||
f->f_frame->frame_obj = f;
|
||||
Py_DECREF(f);
|
||||
return frame->frame_obj;
|
||||
}
|
||||
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
|
||||
assert(frame->owner != FRAME_CLEARED);
|
||||
f->f_frame = frame;
|
||||
frame->frame_obj = f;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue