gh-142589: Fix PyUnstable_Object_IsUniqueReferencedTemporary (gh-142593)

PyUnstable_Object_IsUniqueReferencedTemporary wasn't handling tagged
ints on the evaluation stack properly.
This commit is contained in:
Sam Gross
2025-12-11 14:41:03 -05:00
committed by GitHub
parent dac4589726
commit a26c831bc4
4 changed files with 25 additions and 2 deletions
+7
View File
@@ -251,6 +251,13 @@ class CAPITest(unittest.TestCase):
func(object())
# Test that a newly created object in C is not considered
# a uniquely referenced temporary, because it's not on the stack.
# gh-142586: do the test in a loop over a list to test for handling
# tagged ints on the stack.
for i in [0, 1, 2]:
self.assertFalse(_testcapi.pyobject_is_unique_temporary_new_object())
def pyobject_dump(self, obj, release_gil=False):
pyobject_dump = _testcapi.pyobject_dump
@@ -0,0 +1,2 @@
Fix :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary()` handling of
tagged ints on the interpreter stack.
+10
View File
@@ -138,6 +138,15 @@ pyobject_is_unique_temporary(PyObject *self, PyObject *obj)
return PyLong_FromLong(result);
}
static PyObject *
pyobject_is_unique_temporary_new_object(PyObject *self, PyObject *unused)
{
PyObject *obj = PyList_New(0);
int result = PyUnstable_Object_IsUniqueReferencedTemporary(obj);
Py_DECREF(obj);
return PyLong_FromLong(result);
}
static int MyObject_dealloc_called = 0;
static void
@@ -517,6 +526,7 @@ static PyMethodDef test_methods[] = {
{"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O},
{"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O},
{"pyobject_is_unique_temporary", pyobject_is_unique_temporary, METH_O},
{"pyobject_is_unique_temporary_new_object", pyobject_is_unique_temporary_new_object, METH_NOARGS},
{"test_py_try_inc_ref", test_py_try_inc_ref, METH_NOARGS},
{"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS},
{"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS},
+6 -2
View File
@@ -2759,8 +2759,12 @@ PyUnstable_Object_IsUniqueReferencedTemporary(PyObject *op)
_PyStackRef *stackpointer = frame->stackpointer;
while (stackpointer > base) {
stackpointer--;
if (op == PyStackRef_AsPyObjectBorrow(*stackpointer)) {
return PyStackRef_IsHeapSafe(*stackpointer);
_PyStackRef ref = *stackpointer;
if (PyStackRef_IsTaggedInt(ref)) {
continue;
}
if (op == PyStackRef_AsPyObjectBorrow(ref)) {
return PyStackRef_IsHeapSafe(ref);
}
}
return 0;