Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Doc/c-api/refcounting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,36 @@ objects.
:c:func:`Py_DECREF`, and the same warning applies.


.. c:function:: PyObject* _Py_Borrow(PyObject *o)

:term:`Borrow a reference <borrowed reference>` to an object: decrement the
object reference count and return the object.

The object must not be ``NULL``; if you aren't sure that it isn't
``NULL``, use :c:func:`_Py_XBorrow`.

This function is intended to be used when updating an old C extension to
newer C API functions which return a :term:`strong reference`. For example,
replace ``frame->f_code`` with ``_Py_Borrow(PyFrame_GetCode(frame))``.

If the object can be destroyed before the last usage of the borrowed
Comment thread
vstinner marked this conversation as resolved.
reference, the :c:func:`_Py_Borrow` function should be avoided.

More generally, the :c:func:`_Py_Borrow` function should be avoided whenever
possible.

.. versionadded:: 3.10


.. c:function:: PyObject* _Py_XBorrow(PyObject *o)

Similar to :c:func:`_Py_Borrow`, but the object *o* can be NULL.

If the object *o* is ``NULL``, the function just returns ``NULL``.

.. versionadded:: 3.10


.. c:function:: void Py_CLEAR(PyObject *o)

Decrement the reference count for object *o*. The object may be ``NULL``, in
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,11 @@ New Features
* The :c:func:`PyType_GetSlot` function can accept static types.
(Contributed by Hai Shi and Petr Viktorin in :issue:`41073`.)

* Added :c:func:`_Py_Borrow` and :c:func:`_Py_XBorrow` private functions to
:ref:`borrow a reference <borrowed reference>` to an object: decrement the
object reference count and return the object.
(Contributed by Victor Stinner in :issue:`42522`.)


Porting to Python 3.10
----------------------
Expand Down
15 changes: 15 additions & 0 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,21 @@ static inline PyObject* _Py_XNewRef(PyObject *obj)
#define Py_NewRef(obj) _Py_NewRef(obj)
#define Py_XNewRef(obj) _Py_XNewRef(obj)

// Borrow a reference to an object:
// decrement the object reference count and return the object.
static inline PyObject* _Py_Borrow(PyObject *obj)
{
Py_DECREF(obj);
return obj;
}

// Similar to _Py_Borrow(), but the object can be NULL.
static inline PyObject* _Py_XBorrow(PyObject *obj)
{
Py_XDECREF(obj);
return obj;
}


/*
_Py_NoneStruct is an object of undefined type which can be used in contexts
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added :c:func:`_Py_Borrow` and :c:func:`_Py_XBorrow` functions to :ref:`borrow
a reference <borrowed reference>` to an object: decrement the object reference
count and return the object. Patch by Victor Stinner.
41 changes: 41 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5636,6 +5636,46 @@ test_set_type_size(PyObject* self, PyObject* ignored)
}


static PyObject*
test_refcount(PyObject* self, PyObject* ignored)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: PyObject *self, PyObject *ignored

{
// Test Py_NewRef(), Py_XNewRef(), _Py_Borrow() and _Py_XBorrow()
// functions.
PyObject *obj = PyList_New(0);
if (obj == NULL) {
return NULL;
}
assert(Py_REFCNT(obj) == 1);

PyObject *ref = Py_NewRef(obj);
assert(ref == obj);
assert(Py_REFCNT(obj) == 2);
Py_DECREF(ref);

PyObject *xref = Py_XNewRef(obj);
assert(xref == obj);
assert(Py_REFCNT(obj) == 2);
Py_DECREF(xref);

assert(Py_XNewRef(NULL) == NULL);

Py_INCREF(obj);
PyObject *borrowed = _Py_Borrow(obj);
assert(borrowed == obj);
assert(Py_REFCNT(obj) == 1);

Py_INCREF(obj);
PyObject *xborrowed = _Py_XBorrow(obj);
assert(xborrowed == obj);
assert(Py_REFCNT(obj) == 1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we perhaps also test that Py_XNewRef(NULL) and _Py_XBorrow(NULL) behave as expected?


assert(_Py_XBorrow(NULL) == NULL);

Py_DECREF(obj);
Py_RETURN_NONE;
}


static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS},
{"raise_memoryerror", raise_memoryerror, METH_NOARGS},
Expand Down Expand Up @@ -5908,6 +5948,7 @@ static PyMethodDef TestMethods[] = {
{"pynumber_tobase", pynumber_tobase, METH_VARARGS},
{"without_gc", without_gc, METH_O},
{"test_set_type_size", test_set_type_size, METH_NOARGS},
{"test_refcount", test_refcount, METH_NOARGS},
{NULL, NULL} /* sentinel */
};

Expand Down