https://github.com/python/cpython/commit/f30376c650c40e0819edd9981e45f8ba206fdd83 commit: f30376c650c40e0819edd9981e45f8ba206fdd83 branch: main author: Mark Shannon <m...@hotpy.org> committer: markshannon <m...@hotpy.org> date: 2025-03-12T16:54:10Z summary:
GH-127705: Fix _Py_RefcntAdd to handle objects becoming immortal (GH-131140) files: M Include/internal/pycore_object.h M Include/refcount.h M Objects/unicodeobject.c diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 1c4c3e30fd2f6d..0b686b416ec193 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -135,15 +135,20 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) _Py_INCREF_IMMORTAL_STAT_INC(); return; } -#ifdef Py_REF_DEBUG - _Py_AddRefTotal(_PyThreadState_GET(), n); -#endif -#if !defined(Py_GIL_DISABLED) -#if SIZEOF_VOID_P > 4 - op->ob_refcnt += (PY_UINT32_T)n; -#else - op->ob_refcnt += n; -#endif +#ifndef Py_GIL_DISABLED + Py_ssize_t refcnt = _Py_REFCNT(op); + Py_ssize_t new_refcnt = refcnt + n; + if (new_refcnt >= (Py_ssize_t)_Py_IMMORTAL_MINIMUM_REFCNT) { + new_refcnt = _Py_IMMORTAL_INITIAL_REFCNT; + } +# if SIZEOF_VOID_P > 4 + op->ob_refcnt = (PY_UINT32_T)new_refcnt; +# else + op->ob_refcnt = new_refcnt; +# endif +# ifdef Py_REF_DEBUG + _Py_AddRefTotal(_PyThreadState_GET(), new_refcnt - refcnt); +# endif #else if (_Py_IsOwnedByCurrentThread(op)) { uint32_t local = op->ob_ref_local; @@ -160,6 +165,9 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) else { _Py_atomic_add_ssize(&op->ob_ref_shared, (n << _Py_REF_SHARED_SHIFT)); } +# ifdef Py_REF_DEBUG + _Py_AddRefTotal(_PyThreadState_GET(), n); +# endif #endif // Although the ref count was increased by `n` (which may be greater than 1) // it is only a single increment (i.e. addition) operation, so only 1 refcnt diff --git a/Include/refcount.h b/Include/refcount.h index e66e4aaace3140..ba14bc6965ce3e 100644 --- a/Include/refcount.h +++ b/Include/refcount.h @@ -42,7 +42,8 @@ beyond the refcount limit. Immortality checks for reference count decreases will be done by checking the bit sign flag in the lower 32 bits. */ -#define _Py_IMMORTAL_INITIAL_REFCNT (3UL << 30) +#define _Py_IMMORTAL_INITIAL_REFCNT (3ULL << 30) +#define _Py_IMMORTAL_MINIMUM_REFCNT (1ULL << 31) #define _Py_STATIC_FLAG_BITS ((Py_ssize_t)(_Py_STATICALLY_ALLOCATED_FLAG | _Py_IMMORTAL_FLAGS)) #define _Py_STATIC_IMMORTAL_INITIAL_REFCNT (((Py_ssize_t)_Py_IMMORTAL_INITIAL_REFCNT) | (_Py_STATIC_FLAG_BITS << 48)) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 21ccb01f86bc61..085944cd6bd989 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -15982,7 +15982,7 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) case SSTATE_INTERNED_MORTAL: // Restore 2 references held by the interned dict; these will // be decref'd by clear_interned_dict's PyDict_Clear. - Py_SET_REFCNT(s, Py_REFCNT(s) + 2); + _Py_RefcntAdd(s, 2); #ifdef Py_REF_DEBUG /* let's be pedantic with the ref total */ _Py_IncRefTotal(_PyThreadState_GET()); _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com