diff --git a/Lib/test/test_capi/test_object.py b/Lib/test/test_capi/test_object.py index c5040913e9e1f1..67572ab1ba268d 100644 --- a/Lib/test/test_capi/test_object.py +++ b/Lib/test/test_capi/test_object.py @@ -251,6 +251,13 @@ def func(x): 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 diff --git a/Misc/NEWS.d/next/C_API/2025-12-11-13-01-49.gh-issue-142589.nNAqgw.rst b/Misc/NEWS.d/next/C_API/2025-12-11-13-01-49.gh-issue-142589.nNAqgw.rst new file mode 100644 index 00000000000000..529277b951ada3 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-12-11-13-01-49.gh-issue-142589.nNAqgw.rst @@ -0,0 +1,2 @@ +Fix :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary()` handling of +tagged ints on the interpreter stack. diff --git a/Modules/_testcapi/object.c b/Modules/_testcapi/object.c index 4c9632c07a99f4..a4f76c409c6f78 100644 --- a/Modules/_testcapi/object.c +++ b/Modules/_testcapi/object.c @@ -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}, diff --git a/Objects/object.c b/Objects/object.c index fcea3503de8213..36a37bb0bbea4d 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -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;