Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f30376c

Browse filesBrowse files
authored
GH-127705: Fix _Py_RefcntAdd to handle objects becoming immortal (GH-131140)
1 parent 061da44 commit f30376c
Copy full SHA for f30376c

File tree

Expand file treeCollapse file tree

3 files changed

+20
-11
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+20
-11
lines changed

‎Include/internal/pycore_object.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_object.h
+17-9Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,20 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
135135
_Py_INCREF_IMMORTAL_STAT_INC();
136136
return;
137137
}
138-
#ifdef Py_REF_DEBUG
139-
_Py_AddRefTotal(_PyThreadState_GET(), n);
140-
#endif
141-
#if !defined(Py_GIL_DISABLED)
142-
#if SIZEOF_VOID_P > 4
143-
op->ob_refcnt += (PY_UINT32_T)n;
144-
#else
145-
op->ob_refcnt += n;
146-
#endif
138+
#ifndef Py_GIL_DISABLED
139+
Py_ssize_t refcnt = _Py_REFCNT(op);
140+
Py_ssize_t new_refcnt = refcnt + n;
141+
if (new_refcnt >= (Py_ssize_t)_Py_IMMORTAL_MINIMUM_REFCNT) {
142+
new_refcnt = _Py_IMMORTAL_INITIAL_REFCNT;
143+
}
144+
# if SIZEOF_VOID_P > 4
145+
op->ob_refcnt = (PY_UINT32_T)new_refcnt;
146+
# else
147+
op->ob_refcnt = new_refcnt;
148+
# endif
149+
# ifdef Py_REF_DEBUG
150+
_Py_AddRefTotal(_PyThreadState_GET(), new_refcnt - refcnt);
151+
# endif
147152
#else
148153
if (_Py_IsOwnedByCurrentThread(op)) {
149154
uint32_t local = op->ob_ref_local;
@@ -160,6 +165,9 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
160165
else {
161166
_Py_atomic_add_ssize(&op->ob_ref_shared, (n << _Py_REF_SHARED_SHIFT));
162167
}
168+
# ifdef Py_REF_DEBUG
169+
_Py_AddRefTotal(_PyThreadState_GET(), n);
170+
# endif
163171
#endif
164172
// Although the ref count was increased by `n` (which may be greater than 1)
165173
// it is only a single increment (i.e. addition) operation, so only 1 refcnt

‎Include/refcount.h

Copy file name to clipboardExpand all lines: Include/refcount.h
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ beyond the refcount limit. Immortality checks for reference count decreases will
4242
be done by checking the bit sign flag in the lower 32 bits.
4343
4444
*/
45-
#define _Py_IMMORTAL_INITIAL_REFCNT (3UL << 30)
45+
#define _Py_IMMORTAL_INITIAL_REFCNT (3ULL << 30)
46+
#define _Py_IMMORTAL_MINIMUM_REFCNT (1ULL << 31)
4647
#define _Py_STATIC_FLAG_BITS ((Py_ssize_t)(_Py_STATICALLY_ALLOCATED_FLAG | _Py_IMMORTAL_FLAGS))
4748
#define _Py_STATIC_IMMORTAL_INITIAL_REFCNT (((Py_ssize_t)_Py_IMMORTAL_INITIAL_REFCNT) | (_Py_STATIC_FLAG_BITS << 48))
4849

‎Objects/unicodeobject.c

Copy file name to clipboardExpand all lines: Objects/unicodeobject.c
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15982,7 +15982,7 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
1598215982
case SSTATE_INTERNED_MORTAL:
1598315983
// Restore 2 references held by the interned dict; these will
1598415984
// be decref'd by clear_interned_dict's PyDict_Clear.
15985-
Py_SET_REFCNT(s, Py_REFCNT(s) + 2);
15985+
_Py_RefcntAdd(s, 2);
1598615986
#ifdef Py_REF_DEBUG
1598715987
/* let's be pedantic with the ref total */
1598815988
_Py_IncRefTotal(_PyThreadState_GET());

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.