https://github.com/python/cpython/commit/12d2b95adff88a3395227ec7b28b2c81d879f455
commit: 12d2b95adff88a3395227ec7b28b2c81d879f455
branch: 3.14
author: Sam Gross <[email protected]>
committer: colesbury <[email protected]>
date: 2025-12-11T20:08:45Z
summary:

[3.14] gh-142589: Fix PyUnstable_Object_IsUniqueReferencedTemporary (gh-142593) 
(#142597)

PyUnstable_Object_IsUniqueReferencedTemporary wasn't handling tagged
ints on the evaluation stack properly.
(cherry picked from commit a26c831bc486b6e607cee6a5923bad52b97c2341)

files:
A Misc/NEWS.d/next/C_API/2025-12-11-13-01-49.gh-issue-142589.nNAqgw.rst
M Lib/test/test_capi/test_object.py
M Modules/_testcapi/object.c
M Objects/object.c

diff --git a/Lib/test/test_capi/test_object.py 
b/Lib/test/test_capi/test_object.py
index 98a9a096cfee4d..807b62c19863e7 100644
--- a/Lib/test/test_capi/test_object.py
+++ b/Lib/test/test_capi/test_object.py
@@ -247,5 +247,12 @@ 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())
+
 if __name__ == "__main__":
     unittest.main()
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 798ef97c495aeb..4d53b3c678a470 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
@@ -493,6 +502,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 8dc3ab9643cbb2..b88110faf921a3 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -2631,8 +2631,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;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to