From 03d41f6a19f95b18a8989553f0fbbc4989747e99 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 23 Oct 2026 10:42:41 -0700 Subject: [PATCH 1/3] gh-145921: Clarify return value of tp_traverse --- Doc/c-api/gcsupport.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 9c71bb3d59d5e99..052d739e52ad54a 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -251,6 +251,7 @@ The :c:member:`~PyTypeObject.tp_traverse` handler must have the following type: to the handler. The *visit* function must not be called with a ``NULL`` object argument. If *visit* returns a non-zero value, that value should be returned immediately. + Otherwise, return zero. A typical :c:member:`!tp_traverse` function calls the :c:func:`Py_VISIT` convenience macro on each of the instance's members that are Python @@ -317,6 +318,13 @@ The :c:member:`~PyTypeObject.tp_traverse` handler must have the following type: For a list of safe functions, see a :ref:`separate section ` below. + If an error occurs during traversal, ignore it and return 0. + If ``tp_traverse`` fails to visit some strong references, objects + may become unreachable and waste memory, but correctness won't be affected. + For example, if traversal requires a lock that cannot be acquired promptly, + skip the traversal. + The garbage collector will visit your object again in a future pass. + .. note:: The :c:func:`Py_VISIT` call may be skipped for those members that provably From 2303aaee1fbd25f3c9e1fed0cd02c699cf7f7976 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 23 Oct 2026 10:47:56 -0700 Subject: [PATCH 2/3] Fix Py_VISIT expansion --- Doc/c-api/gcsupport.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 052d739e52ad54a..3d38672a76356cc 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -370,7 +370,7 @@ implementation must name its arguments exactly *visit* and *arg*: This corresponds roughly to:: #define Py_VISIT(o) \ - if (op) { \ + if (o) { \ int visit_result = visit(o, arg); \ if (visit_result != 0) { \ return visit_result; \ From c8f1f2ac0e6723eb8f2ce431bd249c40c18a389f Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 23 Oct 2026 15:27:44 -0700 Subject: [PATCH 3/3] More precise wording --- Doc/c-api/gcsupport.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 3d38672a76356cc..904303274ba075f 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -319,8 +319,9 @@ The :c:member:`~PyTypeObject.tp_traverse` handler must have the following type: :ref:`separate section ` below. If an error occurs during traversal, ignore it and return 0. - If ``tp_traverse`` fails to visit some strong references, objects - may become unreachable and waste memory, but correctness won't be affected. + If ``tp_traverse`` fails to visit some strong references, garbage reference + cycles involving the skipped references will not be reliably broken, + but correctness won't be affected. For example, if traversal requires a lock that cannot be acquired promptly, skip the traversal. The garbage collector will visit your object again in a future pass.