https://github.com/python/cpython/commit/f923605658a29ff9af5a62edc1fc10191977627b
commit: f923605658a29ff9af5a62edc1fc10191977627b
branch: main
author: Peter Bierma <[email protected]>
committer: vstinner <[email protected]>
date: 2024-09-26T12:29:43+02:00
summary:
gh-124538: Fix crash when using `gc.get_referents` on an untracked capsule
object (#124559)
files:
A Misc/NEWS.d/next/Library/2024-09-25-18-34-48.gh-issue-124538.nXZk4R.rst
M Lib/test/test_gc.py
M Objects/capsule.c
diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py
index 906f9884d6792f..bb7df1f5cfa7f7 100644
--- a/Lib/test/test_gc.py
+++ b/Lib/test/test_gc.py
@@ -1048,6 +1048,24 @@ class Z:
callback.assert_not_called()
gc.enable()
+ @cpython_only
+ def test_get_referents_on_capsule(self):
+ # gh-124538: Calling gc.get_referents() on an untracked capsule must
not crash.
+ import _datetime
+ import _socket
+ untracked_capsule = _datetime.datetime_CAPI
+ tracked_capsule = _socket.CAPI
+
+ # For whoever sees this in the future: if this is failing
+ # after making datetime's capsule tracked, that's fine -- this isn't
something
+ # users are relying on. Just find a different capsule that is
untracked.
+ self.assertFalse(gc.is_tracked(untracked_capsule))
+ self.assertTrue(gc.is_tracked(tracked_capsule))
+
+ self.assertEqual(len(gc.get_referents(untracked_capsule)), 0)
+ gc.get_referents(tracked_capsule)
+
+
class IncrementalGCTests(unittest.TestCase):
diff --git
a/Misc/NEWS.d/next/Library/2024-09-25-18-34-48.gh-issue-124538.nXZk4R.rst
b/Misc/NEWS.d/next/Library/2024-09-25-18-34-48.gh-issue-124538.nXZk4R.rst
new file mode 100644
index 00000000000000..33ae037ae56b0b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-09-25-18-34-48.gh-issue-124538.nXZk4R.rst
@@ -0,0 +1 @@
+Fixed crash when using :func:`gc.get_referents` on a capsule object.
diff --git a/Objects/capsule.c b/Objects/capsule.c
index 555979dab2b789..28965e0f21b7a0 100644
--- a/Objects/capsule.c
+++ b/Objects/capsule.c
@@ -317,10 +317,14 @@ static int
capsule_traverse(PyCapsule *capsule, visitproc visit, void *arg)
{
// Capsule object is only tracked by the GC
- // if _PyCapsule_SetTraverse() is called
- assert(capsule->traverse_func != NULL);
+ // if _PyCapsule_SetTraverse() is called, but
+ // this can still be manually triggered by gc.get_referents()
+
+ if (capsule->traverse_func != NULL) {
+ return capsule->traverse_func((PyObject*)capsule, visit, arg);
+ }
- return capsule->traverse_func((PyObject*)capsule, visit, arg);
+ return 0;
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]