]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-152235: Defer GC tracking in more set operations (gh-152273) (gh-152280)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 26 Jun 2026 16:47:23 +0000 (18:47 +0200)
committerGitHub <noreply@github.com>
Fri, 26 Jun 2026 16:47:23 +0000 (01:47 +0900)
gh-152235: Defer GC tracking in more set operations (gh-152273)
(cherry picked from commit a87d24a69d1e97a1e9643c8951d180918ef36e4c)

Co-authored-by: Donghee Na <donghee.na@python.org>
Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-03-16.gh-issue-152235.ZKWiWk.rst [new file with mode: 0644]
Objects/setobject.c

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 (file)
index 0000000..bcc1284
--- /dev/null
@@ -0,0 +1,2 @@
+Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference` and
+:meth:`set.symmetric_difference`. Patch by Donghee Na.
index e00ed6a38c96998213329b03f2e79f160ccb3f55..62ab37bfa766ecb5fe1ef78bf976a3a0ecbe7c50 100644 (file)
@@ -1080,14 +1080,14 @@ set_update_impl(PySetObject *so, PyObject *args)
    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;
@@ -1107,13 +1107,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))
@@ -1121,7 +1129,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 *
@@ -1364,7 +1382,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;
 
@@ -1397,6 +1415,7 @@ set_intersection(PySetObject *so, PyObject *other)
             }
             Py_DECREF(key);
         }
+        _PyObject_GC_TRACK(result);
         return (PyObject *)result;
     }
 
@@ -1428,6 +1447,7 @@ set_intersection(PySetObject *so, PyObject *other)
         Py_DECREF(result);
         return NULL;
     }
+    _PyObject_GC_TRACK(result);
     return (PyObject *)result;
   error:
     Py_DECREF(it);
@@ -1737,7 +1757,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;
 
@@ -1761,6 +1781,7 @@ set_difference(PySetObject *so, PyObject *other)
             }
             Py_DECREF(key);
         }
+        _PyObject_GC_TRACK(result);
         return result;
     }
 
@@ -1784,6 +1805,7 @@ set_difference(PySetObject *so, PyObject *other)
         }
         Py_DECREF(key);
     }
+    _PyObject_GC_TRACK(result);
     return result;
 }
 
@@ -1970,7 +1992,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;
     }
@@ -1982,6 +2005,7 @@ set_symmetric_difference_impl(PySetObject *so, PyObject *other)
         Py_DECREF(result);
         return NULL;
     }
+    _PyObject_GC_TRACK(result);
     return (PyObject *)result;
 }