From 64e11612b5f7eca4d7757a73c316d849d3feac49 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 26 Jun 2026 22:35:17 +0900 Subject: [PATCH] gh-152235: Defer GC tracking in more set operations (gh-152273) (cherry picked from commit a87d24a69d1e97a1e9643c8951d180918ef36e4c) Co-authored-by: Donghee Na --- ...-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst | 2 + Objects/setobject.c | 44 ++++++++++++++----- 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst new file mode 100644 index 000000000000000..bcc128404897da1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst @@ -0,0 +1,2 @@ +Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference` and +:meth:`set.symmetric_difference`. Patch by Donghee Na. diff --git a/Objects/setobject.c b/Objects/setobject.c index 332552aa0822e17..272ca4568119e32 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1137,14 +1137,14 @@ set_update_impl(PySetObject *so, PyObject * const *others, can be retrieved or updated in a single cache line. */ +// Build a set/frozenset left GC-untracked; the caller must _PyObject_GC_TRACK() +// it once fully built, so a half-built set is never exposed during filling. static PyObject * -make_new_set(PyTypeObject *type, PyObject *iterable) +make_new_set_untracked(PyTypeObject *type, PyObject *iterable) { assert(PyType_Check(type)); PySetObject *so; - // Allocate untracked: the fill below runs user code, and a half-built - // set must not be reachable from another thread via gc.get_objects(). so = (PySetObject *)_PyType_AllocNoTrack(type, 0); if (so == NULL) return NULL; @@ -1164,13 +1164,21 @@ make_new_set(PyTypeObject *type, PyObject *iterable) } } - // Track only once fully built. - _PyObject_GC_TRACK(so); return (PyObject *)so; } static PyObject * -make_new_set_basetype(PyTypeObject *type, PyObject *iterable) +make_new_set(PyTypeObject *type, PyObject *iterable) +{ + PyObject *so = make_new_set_untracked(type, iterable); + if (so != NULL) { + _PyObject_GC_TRACK(so); + } + return so; +} + +static PyObject * +make_new_set_basetype_untracked(PyTypeObject *type, PyObject *iterable) { if (type != &PySet_Type && type != &PyFrozenSet_Type) { if (PyType_IsSubtype(type, &PySet_Type)) @@ -1178,7 +1186,17 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable) else type = &PyFrozenSet_Type; } - return make_new_set(type, iterable); + return make_new_set_untracked(type, iterable); +} + +static PyObject * +make_new_set_basetype(PyTypeObject *type, PyObject *iterable) +{ + PyObject *so = make_new_set_basetype_untracked(type, iterable); + if (so != NULL) { + _PyObject_GC_TRACK(so); + } + return so; } static PyObject * @@ -1423,7 +1441,7 @@ set_intersection(PySetObject *so, PyObject *other) if ((PyObject *)so == other) return set_copy_impl(so); - result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL); + result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL); if (result == NULL) return NULL; @@ -1456,6 +1474,7 @@ set_intersection(PySetObject *so, PyObject *other) } Py_DECREF(key); } + _PyObject_GC_TRACK(result); return (PyObject *)result; } @@ -1487,6 +1506,7 @@ set_intersection(PySetObject *so, PyObject *other) Py_DECREF(result); return NULL; } + _PyObject_GC_TRACK(result); return (PyObject *)result; error: Py_DECREF(it); @@ -1801,7 +1821,7 @@ set_difference(PySetObject *so, PyObject *other) return set_copy_and_difference(so, other); } - result = make_new_set_basetype(Py_TYPE(so), NULL); + result = make_new_set_basetype_untracked(Py_TYPE(so), NULL); if (result == NULL) return NULL; @@ -1825,6 +1845,7 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } + _PyObject_GC_TRACK(result); return result; } @@ -1848,6 +1869,7 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } + _PyObject_GC_TRACK(result); return result; } @@ -2037,7 +2059,8 @@ static PyObject * set_symmetric_difference_impl(PySetObject *so, PyObject *other) /*[clinic end generated code: output=270ee0b5d42b0797 input=624f6e7bbdf70db1]*/ { - PySetObject *result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL); + PySetObject *result = + (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL); if (result == NULL) { return NULL; } @@ -2049,6 +2072,7 @@ set_symmetric_difference_impl(PySetObject *so, PyObject *other) Py_DECREF(result); return NULL; } + _PyObject_GC_TRACK(result); return (PyObject *)result; }