summaryrefslogtreecommitdiffstats
path: root/Modules/gcmodule.c
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-02-06 16:45:42 (GMT)
committerGitHub <noreply@github.com>2024-02-06 16:45:42 (GMT)
commit7fdd4235d790559372bbb1bf0c2384191a9bb5f3 (patch)
treef97f2018900b70ca3fdf7c0643e20eef6b511803 /Modules/gcmodule.c
parentf7a22a7055d97c05406512577bdfcb6d3f134b91 (diff)
downloadcpython-7fdd4235d790559372bbb1bf0c2384191a9bb5f3.zip
cpython-7fdd4235d790559372bbb1bf0c2384191a9bb5f3.tar.gz
cpython-7fdd4235d790559372bbb1bf0c2384191a9bb5f3.tar.bz2
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 <Pablogsal@gmail.com>
Diffstat (limited to 'Modules/gcmodule.c')
-rw-r--r--Modules/gcmodule.c41
1 files changed, 28 insertions, 13 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 3b63dd7..3a42654 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -230,6 +230,26 @@ referentsvisit(PyObject *obj, void *arg)
return PyList_Append(list, obj) < 0;
}
+static int
+append_referrents(PyObject *result, PyObject *args)
+{
+ for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(args); i++) {
+ PyObject *obj = PyTuple_GET_ITEM(args, i);
+ if (!_PyObject_IS_GC(obj)) {
+ continue;
+ }
+
+ traverseproc traverse = Py_TYPE(obj)->tp_traverse;
+ if (!traverse) {
+ continue;
+ }
+ if (traverse(obj, referentsvisit, result)) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
/*[clinic input]
gc.get_referents
@@ -242,29 +262,24 @@ static PyObject *
gc_get_referents_impl(PyObject *module, PyObject *args)
/*[clinic end generated code: output=d47dc02cefd06fe8 input=b3ceab0c34038cbf]*/
{
- Py_ssize_t i;
if (PySys_Audit("gc.get_referents", "(O)", args) < 0) {
return NULL;
}
+ PyInterpreterState *interp = _PyInterpreterState_GET();
PyObject *result = PyList_New(0);
if (result == NULL)
return NULL;
- for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
- traverseproc traverse;
- PyObject *obj = PyTuple_GET_ITEM(args, i);
+ // NOTE: stop the world is a no-op in default build
+ _PyEval_StopTheWorld(interp);
+ int err = append_referrents(result, args);
+ _PyEval_StartTheWorld(interp);
- if (!_PyObject_IS_GC(obj))
- continue;
- traverse = Py_TYPE(obj)->tp_traverse;
- if (! traverse)
- continue;
- if (traverse(obj, referentsvisit, result)) {
- Py_DECREF(result);
- return NULL;
- }
+ if (err < 0) {
+ Py_CLEAR(result);
}
+
return result;
}