gh-124538: Fix crash when using `gc.get_referents` on an untracked capsule object (#124559)

This commit is contained in:
Peter Bierma 2024-09-26 06:29:43 -04:00 committed by GitHub
parent 0387c34f7c
commit f923605658
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 26 additions and 3 deletions

View File

@ -1048,6 +1048,24 @@ class GCTests(unittest.TestCase):
callback.assert_not_called() callback.assert_not_called()
gc.enable() 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): class IncrementalGCTests(unittest.TestCase):

View File

@ -0,0 +1 @@
Fixed crash when using :func:`gc.get_referents` on a capsule object.

View File

@ -317,10 +317,14 @@ static int
capsule_traverse(PyCapsule *capsule, visitproc visit, void *arg) capsule_traverse(PyCapsule *capsule, visitproc visit, void *arg)
{ {
// Capsule object is only tracked by the GC // Capsule object is only tracked by the GC
// if _PyCapsule_SetTraverse() is called // if _PyCapsule_SetTraverse() is called, but
assert(capsule->traverse_func != NULL); // 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;
} }