From ac9e4efc41231e0a3316e469c77c7f575db5805a Mon Sep 17 00:00:00 2001 From: Sam Gross <colesbury@gmail.com> Date: Wed, 31 Jan 2024 21:44:04 +0000 Subject: [PATCH 1/3] gh-112529: Stop the world around gc.get_referents 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. --- Modules/gcmodule.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index ffddef34ecce7a..e82d606038e410 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -235,6 +235,25 @@ 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++) { + traverseproc traverse; + PyObject *obj = PyTuple_GET_ITEM(args, i); + + if (!_PyObject_IS_GC(obj)) + continue; + traverse = Py_TYPE(obj)->tp_traverse; + if (! traverse) + continue; + if (traverse(obj, referentsvisit, result)) { + return -1; + } + } + return 0; +} + /*[clinic input] gc.get_referents @@ -247,29 +266,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; } From b76f33b9ceaa86147f518136c7631413e61bbbf9 Mon Sep 17 00:00:00 2001 From: Sam Gross <colesbury@gmail.com> Date: Thu, 1 Feb 2024 11:33:29 -0500 Subject: [PATCH 2/3] Update Modules/gcmodule.c Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com> --- Modules/gcmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index e82d606038e410..94768e56202d61 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -245,7 +245,7 @@ append_referrents(PyObject *result, PyObject *args) if (!_PyObject_IS_GC(obj)) continue; traverse = Py_TYPE(obj)->tp_traverse; - if (! traverse) + if (!traverse) continue; if (traverse(obj, referentsvisit, result)) { return -1; From e689f8b772c02b020f41687ab949d3997e5d3cbb Mon Sep 17 00:00:00 2001 From: Sam Gross <colesbury@gmail.com> Date: Thu, 1 Feb 2024 16:35:38 +0000 Subject: [PATCH 3/3] Add braces to if-statements --- Modules/gcmodule.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 94768e56202d61..a2b66b9b78c169 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -239,14 +239,15 @@ static int append_referrents(PyObject *result, PyObject *args) { for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(args); i++) { - traverseproc traverse; PyObject *obj = PyTuple_GET_ITEM(args, i); - - if (!_PyObject_IS_GC(obj)) + if (!_PyObject_IS_GC(obj)) { continue; - traverse = Py_TYPE(obj)->tp_traverse; - if (!traverse) + } + + traverseproc traverse = Py_TYPE(obj)->tp_traverse; + if (!traverse) { continue; + } if (traverse(obj, referentsvisit, result)) { return -1; }