Skip to content

Commit 9cdc8ba

Browse files
Fix PyFrame_FastToLocals() and PyFrame_LocalsToFast() when the frame has been cleared.
1 parent 362088d commit 9cdc8ba

File tree

1 file changed

+41
-35
lines changed

1 file changed

+41
-35
lines changed

Objects/frameobject.c

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -979,43 +979,48 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
979979

980980
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
981981
PyObject *value = fast[i];
982-
int cellargoffset = CO_CELL_NOT_AN_ARG;
983-
if (co->co_cell2arg != NULL) {
984-
cellargoffset = co->co_cell2arg[i - co->co_nlocals];
985-
}
986-
if (kind & CO_FAST_FREE) {
987-
// The cell was set by _PyEval_MakeFrameVector() from
988-
// the function's closure.
989-
assert(value != NULL && PyCell_Check(value));
990-
value = PyCell_GET(value);
991-
}
992-
else if (kind & CO_FAST_CELL) {
993-
// Note that no *_DEREF ops can happen before MAKE_CELL
994-
// executes. So there's no need to duplicate the work
995-
// that MAKE_CELL would otherwise do later, if it hasn't
996-
// run yet.
997-
if (value != NULL) {
998-
if (PyCell_Check(value) &&
999-
_PyFrame_OpAlreadyRan(f, MAKE_CELL, i)) {
1000-
// (likely) MAKE_CELL must have executed already.
1001-
value = PyCell_GET(value);
1002-
}
1003-
// (unlikely) Otherwise it must be an initial value set
1004-
// by an earlier call to PyFrame_FastToLocals().
982+
if (f->f_state != FRAME_CLEARED) {
983+
int cellargoffset = CO_CELL_NOT_AN_ARG;
984+
if (co->co_cell2arg != NULL) {
985+
cellargoffset = co->co_cell2arg[i - co->co_nlocals];
1005986
}
1006-
else {
1007-
// (unlikely) MAKE_CELL hasn't executed yet.
1008-
if (cellargoffset != CO_CELL_NOT_AN_ARG) {
1009-
// It is an arg that escapes into an inner
1010-
// function so we use the initial value that
1011-
// was already set by _PyEval_MakeFrameVector().
1012-
// Normally the arg value would always be set.
1013-
// However, it can be NULL if it was deleted via
1014-
// PyFrame_LocalsToFast().
1015-
value = fast[cellargoffset];
987+
if (kind & CO_FAST_FREE) {
988+
// The cell was set by _PyEval_MakeFrameVector() from
989+
// the function's closure.
990+
assert(value != NULL && PyCell_Check(value));
991+
value = PyCell_GET(value);
992+
}
993+
else if (kind & CO_FAST_CELL) {
994+
// Note that no *_DEREF ops can happen before MAKE_CELL
995+
// executes. So there's no need to duplicate the work
996+
// that MAKE_CELL would otherwise do later, if it hasn't
997+
// run yet.
998+
if (value != NULL) {
999+
if (PyCell_Check(value) &&
1000+
_PyFrame_OpAlreadyRan(f, MAKE_CELL, i)) {
1001+
// (likely) MAKE_CELL must have executed already.
1002+
value = PyCell_GET(value);
1003+
}
1004+
// (unlikely) Otherwise it must be an initial value set
1005+
// by an earlier call to PyFrame_FastToLocals().
1006+
}
1007+
else {
1008+
// (unlikely) MAKE_CELL hasn't executed yet.
1009+
if (cellargoffset != CO_CELL_NOT_AN_ARG) {
1010+
// It is an arg that escapes into an inner
1011+
// function so we use the initial value that
1012+
// was already set by _PyEval_MakeFrameVector().
1013+
// Normally the arg value would always be set.
1014+
// However, it can be NULL if it was deleted via
1015+
// PyFrame_LocalsToFast().
1016+
value = fast[cellargoffset];
1017+
}
10161018
}
10171019
}
10181020
}
1021+
else {
1022+
assert(value == NULL);
1023+
}
10191024
if (value == NULL) {
10201025
if (PyObject_DelItem(locals, name) != 0) {
10211026
if (PyErr_ExceptionMatches(PyExc_KeyError)) {
@@ -1055,8 +1060,9 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
10551060
PyObject **fast;
10561061
PyObject *error_type, *error_value, *error_traceback;
10571062
PyCodeObject *co;
1058-
if (f == NULL)
1063+
if (f == NULL || f->f_state == FRAME_CLEARED) {
10591064
return;
1065+
}
10601066
locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
10611067
if (locals == NULL)
10621068
return;
@@ -1114,7 +1120,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
11141120
}
11151121
}
11161122
if (cell != NULL) {
1117-
PyObject *oldvalue = PyCell_GET(cell);
1123+
oldvalue = PyCell_GET(cell);
11181124
if (value != oldvalue) {
11191125
Py_XDECREF(oldvalue);
11201126
Py_XINCREF(value);

0 commit comments

Comments
 (0)