From 18edd99f0832b6bae09abf97a5e18a830481bd0c Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Fri, 26 Jun 2026 23:09:37 +0900 Subject: [PATCH 1/2] gh-152235: Defer GC tracking in set.union and set.difference --- ...-06-26-23-09-34.gh-issue-152235.ArozdF.rst | 2 + Objects/setobject.c | 38 +++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-23-09-34.gh-issue-152235.ArozdF.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-23-09-34.gh-issue-152235.ArozdF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-23-09-34.gh-issue-152235.ArozdF.rst new file mode 100644 index 00000000000000..954ea98c9173ac --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-23-09-34.gh-issue-152235.ArozdF.rst @@ -0,0 +1,2 @@ +Defer GC tracking in :meth:`set.union`, :meth:`set.difference` and +:meth:`set.__sub__`. Patch by Donghee Na. diff --git a/Objects/setobject.c b/Objects/setobject.c index d8c38ff1c1d899..0ee46daf94c92f 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1577,6 +1577,21 @@ _PySet_Freeze(PyObject *set) return Py_NewRef(set); } +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 @@ -1589,14 +1604,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; } @@ -1652,7 +1662,8 @@ set_union_impl(PySetObject *so, PyObject * const *others, PyObject *other; Py_ssize_t i; - result = (PySetObject *)set_copy((PyObject *)so, NULL); + result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), + (PyObject *)so); if (result == NULL) return NULL; @@ -1665,6 +1676,7 @@ set_union_impl(PySetObject *so, PyObject * const *others, return NULL; } } + _PyObject_GC_TRACK(result); return (PyObject *)result; } @@ -2059,7 +2071,7 @@ set_copy_and_difference(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) @@ -2118,7 +2130,6 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } - _PyObject_GC_TRACK(result); return result; } @@ -2142,7 +2153,6 @@ set_difference(PySetObject *so, PyObject *other) } Py_DECREF(key); } - _PyObject_GC_TRACK(result); return result; } @@ -2185,6 +2195,7 @@ set_difference_multi_impl(PySetObject *so, PyObject * const *others, return NULL; } } + _PyObject_GC_TRACK(result); return result; } @@ -2199,6 +2210,9 @@ set_sub(PyObject *self, PyObject *other) Py_BEGIN_CRITICAL_SECTION2(so, other); rv = set_difference(so, other); Py_END_CRITICAL_SECTION2(); + if (rv != NULL) { + _PyObject_GC_TRACK(rv); + } return rv; } From eae1642e56396c934c3bad9602933c1665d0cea3 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 27 Jun 2026 01:45:53 +0900 Subject: [PATCH 2/2] Address code review --- .../2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst | 5 +++-- .../2026-06-26-23-09-34.gh-issue-152235.ArozdF.rst | 2 -- Objects/setobject.c | 12 ++++++------ 3 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-23-09-34.gh-issue-152235.ArozdF.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 index bcc128404897da..ff89a2445cb4fe 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/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-23-09-34.gh-issue-152235.ArozdF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-23-09-34.gh-issue-152235.ArozdF.rst deleted file mode 100644 index 954ea98c9173ac..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-23-09-34.gh-issue-152235.ArozdF.rst +++ /dev/null @@ -1,2 +0,0 @@ -Defer GC tracking in :meth:`set.union`, :meth:`set.difference` and -:meth:`set.__sub__`. Patch by Donghee Na. diff --git a/Objects/setobject.c b/Objects/setobject.c index 0ee46daf94c92f..8fdd1eb26118c0 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2067,7 +2067,7 @@ set_difference_update_impl(PySetObject *so, PyObject * const *others, } static PyObject * -set_copy_and_difference(PySetObject *so, PyObject *other) +set_copy_and_difference_untracked(PySetObject *so, PyObject *other) { PyObject *result; @@ -2081,7 +2081,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; @@ -2097,13 +2097,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); @@ -2179,7 +2179,7 @@ set_difference_multi_impl(PySetObject *so, PyObject * const *others, other = others[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; @@ -2208,7 +2208,7 @@ set_sub(PyObject *self, 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);