Skip to content

Commit ce871fd

Browse files
authored
GH-104142: Fix _Py_RefcntAdd to respect immortality (GH-104143)
1 parent fa86a77 commit ce871fd

File tree

3 files changed

+30
-18
lines changed

3 files changed

+30
-18
lines changed

Include/internal/pycore_object.h

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ extern void _Py_DecRefTotal(PyInterpreterState *);
5858
// Increment reference count by n
5959
static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
6060
{
61+
if (_Py_IsImmortal(op)) {
62+
return;
63+
}
6164
#ifdef Py_REF_DEBUG
6265
_Py_AddRefTotal(_PyInterpreterState_GET(), n);
6366
#endif

Lib/test/test_builtin.py

+25-18
Original file line numberDiff line numberDiff line change
@@ -2372,24 +2372,31 @@ def __del__(self):
23722372

23732373
@cpython_only
23742374
class ImmortalTests(unittest.TestCase):
2375-
def test_immortal(self):
2376-
none_refcount = sys.getrefcount(None)
2377-
true_refcount = sys.getrefcount(True)
2378-
false_refcount = sys.getrefcount(False)
2379-
smallint_refcount = sys.getrefcount(100)
2380-
2381-
# Assert that all of these immortal instances have large ref counts.
2382-
self.assertGreater(none_refcount, 2 ** 15)
2383-
self.assertGreater(true_refcount, 2 ** 15)
2384-
self.assertGreater(false_refcount, 2 ** 15)
2385-
self.assertGreater(smallint_refcount, 2 ** 15)
2386-
2387-
# Confirm that the refcount doesn't change even with a new ref to them.
2388-
l = [None, True, False, 100]
2389-
self.assertEqual(sys.getrefcount(None), none_refcount)
2390-
self.assertEqual(sys.getrefcount(True), true_refcount)
2391-
self.assertEqual(sys.getrefcount(False), false_refcount)
2392-
self.assertEqual(sys.getrefcount(100), smallint_refcount)
2375+
2376+
if sys.maxsize < (1 << 32):
2377+
IMMORTAL_REFCOUNT = (1 << 30) - 1
2378+
else:
2379+
IMMORTAL_REFCOUNT = (1 << 32) - 1
2380+
2381+
IMMORTALS = (None, True, False, Ellipsis, NotImplemented, *range(-5, 257))
2382+
2383+
def assert_immortal(self, immortal):
2384+
with self.subTest(immortal):
2385+
self.assertEqual(sys.getrefcount(immortal), self.IMMORTAL_REFCOUNT)
2386+
2387+
def test_immortals(self):
2388+
for immortal in self.IMMORTALS:
2389+
self.assert_immortal(immortal)
2390+
2391+
def test_list_repeat_respect_immortality(self):
2392+
refs = list(self.IMMORTALS) * 42
2393+
for immortal in self.IMMORTALS:
2394+
self.assert_immortal(immortal)
2395+
2396+
def test_tuple_repeat_respect_immortality(self):
2397+
refs = tuple(self.IMMORTALS) * 42
2398+
for immortal in self.IMMORTALS:
2399+
self.assert_immortal(immortal)
23932400

23942401

23952402
class TestType(unittest.TestCase):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix an issue where :class:`list` or :class:`tuple` repetition could fail to
2+
respect :pep:`683`.

0 commit comments

Comments
 (0)