Skip to content

Commit 12d2b95

Browse files
authored
[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 a26c831)
1 parent e09c4de commit 12d2b95

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
@@ -247,5 +247,12 @@ def func(x):
247247

248248
func(object())
249249

250+
# Test that a newly created object in C is not considered
251+
# a uniquely referenced temporary, because it's not on the stack.
252+
# gh-142586: do the test in a loop over a list to test for handling
253+
# tagged ints on the stack.
254+
for i in [0, 1, 2]:
255+
self.assertFalse(_testcapi.pyobject_is_unique_temporary_new_object())
256+
250257
if __name__ == "__main__":
251258
unittest.main()
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
@@ -493,6 +502,7 @@ static PyMethodDef test_methods[] = {
493502
{"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O},
494503
{"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O},
495504
{"pyobject_is_unique_temporary", pyobject_is_unique_temporary, METH_O},
505+
{"pyobject_is_unique_temporary_new_object", pyobject_is_unique_temporary_new_object, METH_NOARGS},
496506
{"test_py_try_inc_ref", test_py_try_inc_ref, METH_NOARGS},
497507
{"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS},
498508
{"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
@@ -2631,8 +2631,12 @@ PyUnstable_Object_IsUniqueReferencedTemporary(PyObject *op)
26312631
_PyStackRef *stackpointer = frame->stackpointer;
26322632
while (stackpointer > base) {
26332633
stackpointer--;
2634-
if (op == PyStackRef_AsPyObjectBorrow(*stackpointer)) {
2635-
return PyStackRef_IsHeapSafe(*stackpointer);
2634+
_PyStackRef ref = *stackpointer;
2635+
if (PyStackRef_IsTaggedInt(ref)) {
2636+
continue;
2637+
}
2638+
if (op == PyStackRef_AsPyObjectBorrow(ref)) {
2639+
return PyStackRef_IsHeapSafe(ref);
26362640
}
26372641
}
26382642
return 0;

0 commit comments

Comments
 (0)