Skip to content

Commit 7fdd423

Browse files
colesburypablogsal
andauthored
gh-112529: Stop the world around gc.get_referents (#114823)
We do not want to add locking in `tp_traverse` slot implementations. Instead, stop the world when calling `gc.get_referents`. Note that the the stop the world call is a no-op in the default build. Co-authored-by: Pablo Galindo Salgado <[email protected]>
1 parent f7a22a7 commit 7fdd423

File tree

1 file changed

+28
-13
lines changed

1 file changed

+28
-13
lines changed

Modules/gcmodule.c

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,26 @@ referentsvisit(PyObject *obj, void *arg)
230230
return PyList_Append(list, obj) < 0;
231231
}
232232

233+
static int
234+
append_referrents(PyObject *result, PyObject *args)
235+
{
236+
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(args); i++) {
237+
PyObject *obj = PyTuple_GET_ITEM(args, i);
238+
if (!_PyObject_IS_GC(obj)) {
239+
continue;
240+
}
241+
242+
traverseproc traverse = Py_TYPE(obj)->tp_traverse;
243+
if (!traverse) {
244+
continue;
245+
}
246+
if (traverse(obj, referentsvisit, result)) {
247+
return -1;
248+
}
249+
}
250+
return 0;
251+
}
252+
233253
/*[clinic input]
234254
gc.get_referents
235255
@@ -242,29 +262,24 @@ static PyObject *
242262
gc_get_referents_impl(PyObject *module, PyObject *args)
243263
/*[clinic end generated code: output=d47dc02cefd06fe8 input=b3ceab0c34038cbf]*/
244264
{
245-
Py_ssize_t i;
246265
if (PySys_Audit("gc.get_referents", "(O)", args) < 0) {
247266
return NULL;
248267
}
268+
PyInterpreterState *interp = _PyInterpreterState_GET();
249269
PyObject *result = PyList_New(0);
250270

251271
if (result == NULL)
252272
return NULL;
253273

254-
for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
255-
traverseproc traverse;
256-
PyObject *obj = PyTuple_GET_ITEM(args, i);
274+
// NOTE: stop the world is a no-op in default build
275+
_PyEval_StopTheWorld(interp);
276+
int err = append_referrents(result, args);
277+
_PyEval_StartTheWorld(interp);
257278

258-
if (!_PyObject_IS_GC(obj))
259-
continue;
260-
traverse = Py_TYPE(obj)->tp_traverse;
261-
if (! traverse)
262-
continue;
263-
if (traverse(obj, referentsvisit, result)) {
264-
Py_DECREF(result);
265-
return NULL;
266-
}
279+
if (err < 0) {
280+
Py_CLEAR(result);
267281
}
282+
268283
return result;
269284
}
270285

0 commit comments

Comments
 (0)