Skip to content

issue with py3.14 Py_REFCNT in Limited API #140153

@da-woods

Description

@da-woods

Bug report

Bug description:

cpython/Include/refcount.h

Lines 95 to 118 in 46f11b3

// Py_REFCNT() implementation for the stable ABI
PyAPI_FUNC(Py_ssize_t) Py_REFCNT(PyObject *ob);
#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030e0000
// Stable ABI implements Py_REFCNT() as a function call
// on limited C API version 3.14 and newer.
#else
static inline Py_ssize_t _Py_REFCNT(PyObject *ob) {
#if !defined(Py_GIL_DISABLED)
return ob->ob_refcnt;
#else
uint32_t local = _Py_atomic_load_uint32_relaxed(&ob->ob_ref_local);
if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
return _Py_IMMORTAL_INITIAL_REFCNT;
}
Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&ob->ob_ref_shared);
return _Py_STATIC_CAST(Py_ssize_t, local) +
Py_ARITHMETIC_RIGHT_SHIFT(Py_ssize_t, shared, _Py_REF_SHARED_SHIFT);
#endif
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_REFCNT(ob) _Py_REFCNT(_PyObject_CAST(ob))
#endif
#endif

In Python 3.14 Py_REFCNT is moved to become a function in the stable ABI. This works fine. If you use a Py_LIMITED_API version less that 3.14 then it generates _Py_REFCNT as an inline function.

On Limited API versions less than 3.11 then it defined Py_REFCNT to be _Py_REFCNT plus a cast. However on Py_LIMITED_API versions between 3.11 and 3.14 then it doesn't work - Py_REFCNT is defined as a function but isn't in the stable ABI.

See wjakob/nanobind#1183 for this in the wild.

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15new features, bugs and security fixestopic-C-APItype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions