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 index bcc128404897da1..ff89a2445cb4fe8 100644 --- 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 @@ -1,2 +1,3 @@ -Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference` and -:meth:`set.symmetric_difference`. Patch by Donghee Na. +Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference`, +:meth:`set.symmetric_difference`, :meth:`set.union` and ``set.__sub__``. +Patch by Donghee Na. diff --git a/Objects/setobject.c b/Objects/setobject.c index 62ab37bfa766ecb..b61c91f397be83a 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1247,6 +1247,21 @@ set_swap_bodies(PySetObject *a, PySetObject *b) } } +static PyObject * +set_copy_untracked_lock_held(PySetObject *so) +{ + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so); + PyObject *copy = make_new_set_basetype_untracked(Py_TYPE(so), NULL); + if (copy == NULL) { + return NULL; + } + if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) { + Py_DECREF(copy); + return NULL; + } + return copy; +} + /*[clinic input] @critical_section set.copy @@ -1259,14 +1274,9 @@ static PyObject * set_copy_impl(PySetObject *so) /*[clinic end generated code: output=c9223a1e1cc6b041 input=c169a4fbb8209257]*/ { - _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so); - PyObject *copy = make_new_set_basetype(Py_TYPE(so), NULL); - if (copy == NULL) { - return NULL; - } - if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) { - Py_DECREF(copy); - return NULL; + PyObject *copy = set_copy_untracked_lock_held(so); + if (copy != NULL) { + _PyObject_GC_TRACK(copy); } return copy; } @@ -1321,7 +1331,8 @@ set_union_impl(PySetObject *so, PyObject *args) PyObject *other; Py_ssize_t i; - result = (PySetObject *)set_copy(so, NULL); + result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), + (PyObject *)so); if (result == NULL) return NULL; @@ -1334,6 +1345,7 @@ set_union_impl(PySetObject *so, PyObject *args) return NULL; } } + _PyObject_GC_TRACK(result); return (PyObject *)result; } @@ -1718,11 +1730,11 @@ set_difference_update_impl(PySetObject *so, PyObject *args) } static PyObject * -set_copy_and_difference(PySetObject *so, PyObject *other) +set_copy_and_difference_untracked(PySetObject *so, PyObject *other) { PyObject *result; - result = set_copy_impl(so); + result = set_copy_untracked_lock_held(so); if (result == NULL) return NULL; if (set_difference_update_internal((PySetObject *) result, other) == 0) @@ -1732,7 +1744,7 @@ set_copy_and_difference(PySetObject *so, PyObject *other) } static PyObject * -set_difference(PySetObject *so, PyObject *other) +set_difference_untracked(PySetObject *so, PyObject *other) { PyObject *result; PyObject *key; @@ -1748,13 +1760,13 @@ set_difference(PySetObject *so, PyObject *other) other_size = PyDict_GET_SIZE(other); } else { - return set_copy_and_difference(so, other); + return set_copy_and_difference_untracked(so, other); } /* If len(so) much more than len(other), it's more efficient to simply copy * so and then iterate other looking for common elements. */ if ((PySet_GET_SIZE(so) >> 2) > other_size) { - return set_copy_and_difference(so, other); + return set_copy_and_difference_untracked(so, other); } result = make_new_set_basetype_untracked(Py_TYPE(so), NULL); @@ -1781,7 +1793,6 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } - _PyObject_GC_TRACK(result); return result; } @@ -1805,7 +1816,6 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } - _PyObject_GC_TRACK(result); return result; } @@ -1830,7 +1840,7 @@ set_difference_multi_impl(PySetObject *so, PyObject *args) other = PyTuple_GET_ITEM(args, 0); Py_BEGIN_CRITICAL_SECTION2(so, other); - result = set_difference(so, other); + result = set_difference_untracked(so, other); Py_END_CRITICAL_SECTION2(); if (result == NULL) return NULL; @@ -1846,6 +1856,7 @@ set_difference_multi_impl(PySetObject *so, PyObject *args) return NULL; } } + _PyObject_GC_TRACK(result); return result; } @@ -1857,8 +1868,11 @@ set_sub(PySetObject *so, PyObject *other) PyObject *rv; Py_BEGIN_CRITICAL_SECTION2(so, other); - rv = set_difference(so, other); + rv = set_difference_untracked(so, other); Py_END_CRITICAL_SECTION2(); + if (rv != NULL) { + _PyObject_GC_TRACK(rv); + } return rv; }