Skip to content

Commit a26c831

Browse files
authored
gh-142589: Fix PyUnstable_Object_IsUniqueReferencedTemporary (gh-142593)
PyUnstable_Object_IsUniqueReferencedTemporary wasn't handling tagged ints on the evaluation stack properly.
1 parent dac4589 commit a26c831

File tree

4 files changed

+25
-2
lines changed

4 files changed

+25
-2
lines changed

‎Lib/test/test_capi/test_object.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,13 @@ def func(x):
251251

252252
func(object())
253253

254+
# Test that a newly created object in C is not considered
255+
# a uniquely referenced temporary, because it's not on the stack.
256+
# gh-142586: do the test in a loop over a list to test for handling
257+
# tagged ints on the stack.
258+
for i in [0, 1, 2]:
259+
self.assertFalse(_testcapi.pyobject_is_unique_temporary_new_object())
260+
254261
def pyobject_dump(self, obj, release_gil=False):
255262
pyobject_dump = _testcapi.pyobject_dump
256263

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary()` handling of
2+
tagged ints on the interpreter stack.

‎Modules/_testcapi/object.c‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ pyobject_is_unique_temporary(PyObject *self, PyObject *obj)
138138
return PyLong_FromLong(result);
139139
}
140140

141+
static PyObject *
142+
pyobject_is_unique_temporary_new_object(PyObject *self, PyObject *unused)
143+
{
144+
PyObject *obj = PyList_New(0);
145+
int result = PyUnstable_Object_IsUniqueReferencedTemporary(obj);
146+
Py_DECREF(obj);
147+
return PyLong_FromLong(result);
148+
}
149+
141150
static int MyObject_dealloc_called = 0;
142151

143152
static void
@@ -517,6 +526,7 @@ static PyMethodDef test_methods[] = {
517526
{"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O},
518527
{"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O},
519528
{"pyobject_is_unique_temporary", pyobject_is_unique_temporary, METH_O},
529+
{"pyobject_is_unique_temporary_new_object", pyobject_is_unique_temporary_new_object, METH_NOARGS},
520530
{"test_py_try_inc_ref", test_py_try_inc_ref, METH_NOARGS},
521531
{"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS},
522532
{"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS},

‎Objects/object.c‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2759,8 +2759,12 @@ PyUnstable_Object_IsUniqueReferencedTemporary(PyObject *op)
27592759
_PyStackRef *stackpointer = frame->stackpointer;
27602760
while (stackpointer > base) {
27612761
stackpointer--;
2762-
if (op == PyStackRef_AsPyObjectBorrow(*stackpointer)) {
2763-
return PyStackRef_IsHeapSafe(*stackpointer);
2762+
_PyStackRef ref = *stackpointer;
2763+
if (PyStackRef_IsTaggedInt(ref)) {
2764+
continue;
2765+
}
2766+
if (op == PyStackRef_AsPyObjectBorrow(ref)) {
2767+
return PyStackRef_IsHeapSafe(ref);
27642768
}
27652769
}
27662770
return 0;

0 commit comments

Comments
 (0)