Skip to content

Commit f53b312

Browse files
committed
gh-120321: Make gen.gi_frame.clear() thread-safe
1 parent f783cc3 commit f53b312

File tree

3 files changed

+39
-21
lines changed

3 files changed

+39
-21
lines changed

Include/internal/pycore_genobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ PyGenObject *_PyGen_GetGeneratorFromFrame(_PyInterpreterFrame *frame)
2222
}
2323

2424
PyAPI_FUNC(PyObject *)_PyGen_yf(PyGenObject *);
25-
extern void _PyGen_Finalize(PyObject *self);
25+
extern int _PyGen_ClearFrame(PyGenObject *self);
2626

2727
// Export for '_asyncio' shared extension
2828
PyAPI_FUNC(int) _PyGen_SetStopIterationValue(PyObject *);

Objects/frameobject.c

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,30 +2016,20 @@ frame_clear_impl(PyFrameObject *self)
20162016
{
20172017
if (self->f_frame->owner == FRAME_OWNED_BY_GENERATOR) {
20182018
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(self->f_frame);
2019-
if (gen->gi_frame_state == FRAME_EXECUTING) {
2020-
goto running;
2021-
}
2022-
if (FRAME_STATE_SUSPENDED(gen->gi_frame_state)) {
2023-
goto suspended;
2019+
if (_PyGen_ClearFrame(gen) < 0) {
2020+
return NULL;
20242021
}
2025-
_PyGen_Finalize((PyObject *)gen);
20262022
}
20272023
else if (self->f_frame->owner == FRAME_OWNED_BY_THREAD) {
2028-
goto running;
2024+
PyErr_SetString(PyExc_RuntimeError,
2025+
"cannot clear an executing frame");
2026+
return NULL;
20292027
}
20302028
else {
20312029
assert(self->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT);
20322030
(void)frame_tp_clear((PyObject *)self);
20332031
}
20342032
Py_RETURN_NONE;
2035-
running:
2036-
PyErr_SetString(PyExc_RuntimeError,
2037-
"cannot clear an executing frame");
2038-
return NULL;
2039-
suspended:
2040-
PyErr_SetString(PyExc_RuntimeError,
2041-
"cannot clear a suspended frame");
2042-
return NULL;
20432033
}
20442034

20452035
/*[clinic input]

Objects/genobject.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ gen_traverse(PyObject *self, visitproc visit, void *arg)
9191
return 0;
9292
}
9393

94-
void
95-
_PyGen_Finalize(PyObject *self)
94+
static void
95+
gen_finalize(PyObject *self)
9696
{
9797
PyGenObject *gen = (PyGenObject *)self;
9898

@@ -160,6 +160,34 @@ gen_clear_frame(PyGenObject *gen)
160160
_PyErr_ClearExcState(&gen->gi_exc_state);
161161
}
162162

163+
int
164+
_PyGen_ClearFrame(PyGenObject *gen)
165+
{
166+
int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state);
167+
do {
168+
if (FRAME_STATE_FINISHED(frame_state)) {
169+
return 0;
170+
}
171+
else if (frame_state == FRAME_EXECUTING) {
172+
PyErr_SetString(PyExc_RuntimeError,
173+
"cannot clear an executing frame");
174+
return -1;
175+
}
176+
else if (FRAME_STATE_SUSPENDED(frame_state)) {
177+
PyErr_SetString(PyExc_RuntimeError,
178+
"cannot clear an suspended frame");
179+
return -1;
180+
}
181+
assert(frame_state == FRAME_CREATED);
182+
} while (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_CLEARED));
183+
184+
if (_PyGen_GetCode(gen)->co_flags & CO_COROUTINE) {
185+
_PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
186+
}
187+
gen_clear_frame(gen);
188+
return 0;
189+
}
190+
163191
static void
164192
gen_dealloc(PyObject *self)
165193
{
@@ -1006,7 +1034,7 @@ PyTypeObject PyGen_Type = {
10061034
0, /* tp_weaklist */
10071035
0, /* tp_del */
10081036
0, /* tp_version_tag */
1009-
_PyGen_Finalize, /* tp_finalize */
1037+
gen_finalize, /* tp_finalize */
10101038
};
10111039

10121040
static PyObject *
@@ -1336,7 +1364,7 @@ PyTypeObject PyCoro_Type = {
13361364
0, /* tp_weaklist */
13371365
0, /* tp_del */
13381366
0, /* tp_version_tag */
1339-
_PyGen_Finalize, /* tp_finalize */
1367+
gen_finalize, /* tp_finalize */
13401368
};
13411369

13421370
static void
@@ -1762,7 +1790,7 @@ PyTypeObject PyAsyncGen_Type = {
17621790
0, /* tp_weaklist */
17631791
0, /* tp_del */
17641792
0, /* tp_version_tag */
1765-
_PyGen_Finalize, /* tp_finalize */
1793+
gen_finalize, /* tp_finalize */
17661794
};
17671795

17681796

0 commit comments

Comments
 (0)