]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-152235: Defer GC tracking in set.union and set.difference (gh-152290) ...
authorDonghee Na <donghee.na@python.org>
Fri, 26 Jun 2026 17:54:25 +0000 (02:54 +0900)
committerGitHub <noreply@github.com>
Fri, 26 Jun 2026 17:54:25 +0000 (17:54 +0000)
(cherry picked from commit 5a549e82b81378cb294904dab49cbee853bddd64)

Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst
Objects/setobject.c

index bcc128404897da1dd46029a059de61b69ab46c8d..ff89a2445cb4fe8a43c455dd535a030a46d7da36 100644 (file)
@@ -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.
index aec73993451f654d5237265160ff8a42e12127b8..bb407ceabadf1c8ffe2234a6e9eb016d6ce28bf6 100644 (file)
@@ -1567,6 +1567,21 @@ set_swap_bodies(PySetObject *a, PySetObject *b)
     FT_ATOMIC_STORE_PTR_RELEASE(b->table, b_table);
 }
 
+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
@@ -1579,14 +1594,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;
 }
@@ -1642,7 +1652,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;
 
@@ -1655,6 +1666,7 @@ set_union_impl(PySetObject *so, PyObject * const *others,
             return NULL;
         }
     }
+    _PyObject_GC_TRACK(result);
     return (PyObject *)result;
 }
 
@@ -2045,11 +2057,11 @@ 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;
 
-    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)
@@ -2059,7 +2071,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;
@@ -2075,13 +2087,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);
@@ -2108,7 +2120,6 @@ set_difference(PySetObject *so, PyObject *other)
             }
             Py_DECREF(key);
         }
-        _PyObject_GC_TRACK(result);
         return result;
     }
 
@@ -2132,7 +2143,6 @@ set_difference(PySetObject *so, PyObject *other)
         }
         Py_DECREF(key);
     }
-    _PyObject_GC_TRACK(result);
     return result;
 }
 
@@ -2159,7 +2169,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;
@@ -2175,6 +2185,7 @@ set_difference_multi_impl(PySetObject *so, PyObject * const *others,
             return NULL;
         }
     }
+    _PyObject_GC_TRACK(result);
     return result;
 }
 
@@ -2187,8 +2198,11 @@ 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);
+    }
     return rv;
 }