diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 9d01254ddb2a11..1bb5c1b768510f 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -123,9 +123,12 @@ the :mod:`io` APIs instead. Write object *obj* to file object *p*. The only supported flag for *flags* is :c:macro:`Py_PRINT_RAW`; if given, the :func:`str` of the object is written - instead of the :func:`repr`. Return ``0`` on success or ``-1`` on failure; the - appropriate exception will be set. + instead of the :func:`repr`. + + If *obj* is ``NULL``, write the string ``""``. + Return ``0`` on success or ``-1`` on failure; the + appropriate exception will be set. .. c:function:: int PyFile_WriteString(const char *s, PyObject *p) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 416465c2a42096..be4e5847022f33 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -319,6 +319,8 @@ Object Protocol representation on success, ``NULL`` on failure. This is the equivalent of the Python expression ``repr(o)``. Called by the :func:`repr` built-in function. + If argument is ``NULL``, return the string ``''``. + .. versionchanged:: 3.4 This function now includes a debug assertion to help ensure that it does not silently discard an active exception. @@ -333,6 +335,8 @@ Object Protocol a string similar to that returned by :c:func:`PyObject_Repr` in Python 2. Called by the :func:`ascii` built-in function. + If argument is ``NULL``, return the string ``''``. + .. index:: string; PyObject_Str (C function) @@ -343,6 +347,8 @@ Object Protocol Python expression ``str(o)``. Called by the :func:`str` built-in function and, therefore, by the :func:`print` function. + If argument is ``NULL``, return the string ``''``. + .. versionchanged:: 3.4 This function now includes a debug assertion to help ensure that it does not silently discard an active exception. @@ -358,6 +364,8 @@ Object Protocol a TypeError is raised when *o* is an integer instead of a zero-initialized bytes object. + If argument is ``NULL``, return the :class:`bytes` object ``b''``. + .. c:function:: int PyObject_IsSubclass(PyObject *derived, PyObject *cls) diff --git a/Lib/test/test_capi/test_list.py b/Lib/test/test_capi/test_list.py index 52d8bf3ff47f23..bb330e17739633 100644 --- a/Lib/test/test_capi/test_list.py +++ b/Lib/test/test_capi/test_list.py @@ -352,6 +352,10 @@ def test_list_extend(self): # CRASHES list_extend(NULL, []) # CRASHES list_extend([], NULL) + def test_uninitialized_list_repr(self): + lst = _testlimitedcapi.list_new(3) + self.assertEqual(repr(lst), '[, , ]') + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_capi/test_tuple.py b/Lib/test/test_capi/test_tuple.py index e6b49caeb51f32..eaeb99cf153506 100644 --- a/Lib/test/test_capi/test_tuple.py +++ b/Lib/test/test_capi/test_tuple.py @@ -257,5 +257,10 @@ def test__tuple_resize(self): self.assertRaises(SystemError, resize, [1, 2, 3], 0, False) self.assertRaises(SystemError, resize, NULL, 0, False) + def test_uninitialized_tuple_repr(self): + tup = _testlimitedcapi.tuple_new(3) + self.assertEqual(repr(tup), '(, , )') + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-18-18-52-00.gh-issue-146056.r1tVSo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-18-18-52-00.gh-issue-146056.r1tVSo.rst new file mode 100644 index 00000000000000..5d978869ecc8da --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-18-18-52-00.gh-issue-146056.r1tVSo.rst @@ -0,0 +1 @@ +Fix :func:`repr` for lists containing ``NULL``\ s. diff --git a/Objects/listobject.c b/Objects/listobject.c index 8af6964189ec3e..f5acc5c1bef4ee 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -604,7 +604,7 @@ list_repr_impl(PyListObject *v) so must refetch the list size on each iteration. */ for (i = 0; i < Py_SIZE(v); ++i) { /* Hold a strong reference since repr(item) can mutate the list */ - item = Py_NewRef(v->ob_item[i]); + item = Py_XNewRef(v->ob_item[i]); if (i > 0) { if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0)