From eb71cca96b3d907943325fac24f7a9625d982f42 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Fri, 13 Mar 2026 02:00:25 +0500 Subject: [PATCH 01/14] Use _PyTuple_FromPair[Steal] in Objects --- Objects/codeobject.c | 14 +++++++------- Objects/dictobject.c | 25 ++++++------------------- Objects/enumobject.c | 20 +++----------------- Objects/floatobject.c | 4 +++- Objects/frameobject.c | 8 +++----- Objects/listobject.c | 2 +- Objects/longobject.c | 22 ++++------------------ Objects/odictobject.c | 14 +++++--------- Objects/stringlib/unicode_format.h | 7 +++++-- Objects/typeobject.c | 5 +++-- Objects/typevarobject.c | 3 ++- 11 files changed, 42 insertions(+), 82 deletions(-) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index d26516f7c2ff66..4d537f329b31bf 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -3050,7 +3050,7 @@ _PyCode_ConstantKey(PyObject *op) else if (PyBool_Check(op) || PyBytes_CheckExact(op)) { /* Make booleans different from integers 0 and 1. * Avoid BytesWarning from comparing bytes with strings. */ - key = PyTuple_Pack(2, Py_TYPE(op), op); + key = _PyTuple_FromPair((PyObject *)Py_TYPE(op), op); } else if (PyFloat_CheckExact(op)) { double d = PyFloat_AS_DOUBLE(op); @@ -3060,7 +3060,7 @@ _PyCode_ConstantKey(PyObject *op) if (d == 0.0 && copysign(1.0, d) < 0.0) key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None); else - key = PyTuple_Pack(2, Py_TYPE(op), op); + key = _PyTuple_FromPair((PyObject *)Py_TYPE(op), op); } else if (PyComplex_CheckExact(op)) { Py_complex z; @@ -3084,7 +3084,7 @@ _PyCode_ConstantKey(PyObject *op) key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None); } else { - key = PyTuple_Pack(2, Py_TYPE(op), op); + key = _PyTuple_FromPair((PyObject *)Py_TYPE(op), op); } } else if (PyTuple_CheckExact(op)) { @@ -3109,7 +3109,7 @@ _PyCode_ConstantKey(PyObject *op) PyTuple_SET_ITEM(tuple, i, item_key); } - key = PyTuple_Pack(2, tuple, op); + key = _PyTuple_FromPair(tuple, op); Py_DECREF(tuple); } else if (PyFrozenSet_CheckExact(op)) { @@ -3143,7 +3143,7 @@ _PyCode_ConstantKey(PyObject *op) if (set == NULL) return NULL; - key = PyTuple_Pack(2, set, op); + key = _PyTuple_FromPair(set, op); Py_DECREF(set); return key; } @@ -3174,7 +3174,7 @@ _PyCode_ConstantKey(PyObject *op) goto slice_exit; } - key = PyTuple_Pack(2, slice_key, op); + key = _PyTuple_FromPair(slice_key, op); Py_DECREF(slice_key); slice_exit: Py_XDECREF(start_key); @@ -3188,7 +3188,7 @@ _PyCode_ConstantKey(PyObject *op) if (obj_id == NULL) return NULL; - key = PyTuple_Pack(2, obj_id, op); + key = _PyTuple_FromPair(obj_id, op); Py_DECREF(obj_id); } return key; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 842d9be73b8792..6aedc3f5fe1672 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5439,7 +5439,7 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype) } if (itertype == &PyDictIterItem_Type || itertype == &PyDictRevIterItem_Type) { - di->di_result = PyTuple_Pack(2, Py_None, Py_None); + di->di_result = _PyTuple_FromPairSteal(Py_None, Py_None); if (di->di_result == NULL) { Py_DECREF(di); return NULL; @@ -6005,14 +6005,7 @@ dictiter_iternextitem(PyObject *self) _PyTuple_Recycle(result); } else { - result = PyTuple_New(2); - if (result == NULL) { - Py_DECREF(key); - Py_DECREF(value); - return NULL; - } - PyTuple_SET_ITEM(result, 0, key); - PyTuple_SET_ITEM(result, 1, value); + result = _PyTuple_FromPairSteal(key, value); } return result; } @@ -6131,12 +6124,7 @@ dictreviter_iter_lock_held(PyDictObject *d, PyObject *self) _PyTuple_Recycle(result); } else { - result = PyTuple_New(2); - if (result == NULL) { - return NULL; - } - PyTuple_SET_ITEM(result, 0, Py_NewRef(key)); - PyTuple_SET_ITEM(result, 1, Py_NewRef(value)); + result = _PyTuple_FromPair(key, value); } return result; } @@ -6629,6 +6617,7 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) else { Py_INCREF(val1); to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ); + Py_DECREF(val1); if (to_delete < 0) { goto error; } @@ -6640,7 +6629,8 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) } } else { - PyObject *pair = PyTuple_Pack(2, key, val2); + PyObject *pair = _PyTuple_FromPairSteal(key, val2); + key = val2 = NULL; if (pair == NULL) { goto error; } @@ -6650,9 +6640,6 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) } Py_DECREF(pair); } - Py_DECREF(key); - Py_XDECREF(val1); - Py_DECREF(val2); } key = val1 = val2 = NULL; diff --git a/Objects/enumobject.c b/Objects/enumobject.c index 70e7cce6aba008..d7cad67a0e30a0 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -78,7 +78,7 @@ enum_new_impl(PyTypeObject *type, PyObject *iterable, PyObject *start) Py_DECREF(en); return NULL; } - en->en_result = PyTuple_Pack(2, Py_None, Py_None); + en->en_result = _PyTuple_FromPairSteal(Py_None, Py_None); if (en->en_result == NULL) { Py_DECREF(en); return NULL; @@ -226,14 +226,7 @@ enum_next_long(enumobject *en, PyObject* next_item) _PyTuple_Recycle(result); return result; } - result = PyTuple_New(2); - if (result == NULL) { - Py_DECREF(next_index); - Py_DECREF(next_item); - return NULL; - } - PyTuple_SET_ITEM(result, 0, next_index); - PyTuple_SET_ITEM(result, 1, next_item); + result = _PyTuple_FromPairSteal(next_index, next_item); return result; } @@ -276,14 +269,7 @@ enum_next(PyObject *op) _PyTuple_Recycle(result); return result; } - result = PyTuple_New(2); - if (result == NULL) { - Py_DECREF(next_index); - Py_DECREF(next_item); - return NULL; - } - PyTuple_SET_ITEM(result, 0, next_index); - PyTuple_SET_ITEM(result, 1, next_item); + result = _PyTuple_FromPairSteal(next_index, next_item); return result; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 18871a4f3c51a9..33eded3acea321 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -16,6 +16,7 @@ #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_stackref.h" // PyStackRef_AsPyObjectBorrow() #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() +#include "pycore_tuple.h" // _PyTuple_FromPair #include // DBL_MAX #include // strtol() @@ -1540,7 +1541,8 @@ float_as_integer_ratio_impl(PyObject *self) goto error; } - result_pair = PyTuple_Pack(2, numerator, denominator); + result_pair = _PyTuple_FromPairSteal(numerator, denominator); + numerator = denominator = NULL; error: Py_XDECREF(py_exponent); diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 9a7abfc0ec26ab..1cfdc7105ad5f2 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -13,6 +13,7 @@ #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_opcode_metadata.h" // _PyOpcode_Caches #include "pycore_optimizer.h" // _Py_Executors_InvalidateDependency() +#include "pycore_tuple.h" // _PyTuple_FromPair #include "pycore_unicodeobject.h" // _PyUnicode_Equal() #include "frameobject.h" // PyFrameLocalsProxyObject @@ -630,22 +631,19 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored)) PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i); if (value) { - PyObject *pair = PyTuple_Pack(2, name, value); + PyObject *pair = _PyTuple_FromPairSteal(Py_NewRef(name), value); if (pair == NULL) { Py_DECREF(items); - Py_DECREF(value); return NULL; } if (PyList_Append(items, pair) < 0) { Py_DECREF(items); Py_DECREF(pair); - Py_DECREF(value); return NULL; } Py_DECREF(pair); - Py_DECREF(value); } } @@ -655,7 +653,7 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored)) PyObject *key = NULL; PyObject *value = NULL; while (PyDict_Next(frame->f_extra_locals, &j, &key, &value)) { - PyObject *pair = PyTuple_Pack(2, key, value); + PyObject *pair = _PyTuple_FromPair(key, value); if (pair == NULL) { Py_DECREF(items); return NULL; diff --git a/Objects/listobject.c b/Objects/listobject.c index 1cc62764e2fd8c..390a5899c42930 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1439,7 +1439,7 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict) Py_ssize_t i = 0; PyObject *key_value[2]; while (_PyDict_Next((PyObject *)dict, &pos, &key_value[0], &key_value[1], NULL)) { - PyObject *item = PyTuple_FromArray(key_value, 2); + PyObject *item = _PyTuple_FromPair(key_value[0], key_value[1]); if (item == NULL) { Py_SET_SIZE(self, m + i); return -1; diff --git a/Objects/longobject.c b/Objects/longobject.c index 185226db43a92a..782c102f2289fe 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -12,6 +12,7 @@ #include "pycore_runtime.h" // _PY_NSMALLPOSINTS #include "pycore_stackref.h" #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() +#include "pycore_tuple.h" // _PyTuple_FromPairSteal #include "pycore_unicodeobject.h" // _PyUnicode_Equal() #include // DBL_MANT_DIG @@ -4886,15 +4887,7 @@ long_divmod(PyObject *a, PyObject *b) if (l_divmod((PyLongObject*)a, (PyLongObject*)b, &div, &mod) < 0) { return NULL; } - z = PyTuple_New(2); - if (z != NULL) { - PyTuple_SET_ITEM(z, 0, (PyObject *) div); - PyTuple_SET_ITEM(z, 1, (PyObject *) mod); - } - else { - Py_DECREF(div); - Py_DECREF(mod); - } + z = _PyTuple_FromPairSteal((PyObject *)div, (PyObject *)mod); return z; } @@ -6185,13 +6178,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) goto error; } - result = PyTuple_New(2); - if (result == NULL) - goto error; - - /* PyTuple_SET_ITEM steals references */ - PyTuple_SET_ITEM(result, 0, (PyObject *)quo); - PyTuple_SET_ITEM(result, 1, (PyObject *)rem); + result = _PyTuple_FromPairSteal((PyObject *)quo, (PyObject *)rem); return result; error: @@ -6374,8 +6361,7 @@ int_as_integer_ratio_impl(PyObject *self) if (numerator == NULL) { return NULL; } - ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_GetOne()); - Py_DECREF(numerator); + ratio_tuple = _PyTuple_FromPairSteal(numerator, _PyLong_GetOne()); return ratio_tuple; } diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 25928028919c9c..786e584a3b83bf 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1171,9 +1171,7 @@ OrderedDict_popitem_impl(PyODictObject *self, int last) value = _odict_popkey_hash((PyObject *)self, key, NULL, _odictnode_HASH(node)); if (value == NULL) return NULL; - item = PyTuple_Pack(2, key, value); - Py_DECREF(key); - Py_DECREF(value); + item = _PyTuple_FromPairSteal(key, value); return item; } @@ -1828,18 +1826,16 @@ odictiter_iternext_lock_held(PyObject *op) // bpo-42536: The GC may have untracked this result tuple. Since we're // recycling it, make sure it's tracked again: _PyTuple_Recycle(result); + PyTuple_SET_ITEM(result, 0, key); /* steals reference */ + PyTuple_SET_ITEM(result, 1, value); /* steals reference */ } else { - result = PyTuple_New(2); + result = _PyTuple_FromPairSteal(key, value); if (result == NULL) { - Py_DECREF(key); - Py_DECREF(value); goto done; } } - PyTuple_SET_ITEM(result, 0, key); /* steals reference */ - PyTuple_SET_ITEM(result, 1, value); /* steals reference */ return result; done: @@ -1933,7 +1929,7 @@ odictiter_new(PyODictObject *od, int kind) return NULL; if ((kind & _odict_ITER_ITEMS) == _odict_ITER_ITEMS) { - di->di_result = PyTuple_Pack(2, Py_None, Py_None); + di->di_result = _PyTuple_FromPairSteal(Py_None, Py_None); if (di->di_result == NULL) { Py_DECREF(di); return NULL; diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h index ff32db65b11a0b..e591ce50e7d947 100644 --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -4,6 +4,7 @@ #include "pycore_complexobject.h" // _PyComplex_FormatAdvancedWriter() #include "pycore_floatobject.h" // _PyFloat_FormatAdvancedWriter() +#include "pycore_tuple.h" // _PyTuple_FromPairSteal /************************************************************************/ /*********** Global data structures and forward declarations *********/ @@ -1183,7 +1184,8 @@ fieldnameiter_next(PyObject *op) goto done; /* return a tuple of values */ - result = PyTuple_Pack(2, is_attr_obj, obj); + result = _PyTuple_FromPairSteal(is_attr_obj, obj); + return result; done: Py_XDECREF(is_attr_obj); @@ -1274,7 +1276,8 @@ formatter_field_name_split(PyObject *Py_UNUSED(module), PyObject *self) goto done; /* return a tuple of values */ - result = PyTuple_Pack(2, first_obj, it); + result = _PyTuple_FromPairSteal(first_obj, (PyObject *)it); + return result; done: Py_XDECREF(it); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2a818f5f0205fd..3903efd8c1457b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -19,6 +19,7 @@ #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // _Py_Mangle() +#include "pycore_tuple.h" // _PyTuple_FromPair #include "pycore_typeobject.h" // struct type_cache #include "pycore_unicodeobject.h" // _PyUnicode_Copy #include "pycore_unionobject.h" // _Py_union_type_or @@ -1782,7 +1783,7 @@ mro_hierarchy_for_complete_type(PyTypeObject *type, PyObject *temp) tuple = PyTuple_Pack(3, type, new_mro, old_mro); } else { - tuple = PyTuple_Pack(2, type, new_mro); + tuple = _PyTuple_FromPair((PyObject *)type, new_mro); } if (tuple != NULL) { @@ -7826,7 +7827,7 @@ object_getstate_default(PyObject *obj, int required) if (PyDict_GET_SIZE(slots) > 0) { PyObject *state2; - state2 = PyTuple_Pack(2, state, slots); + state2 = _PyTuple_FromPair(state, slots); Py_DECREF(state); if (state2 == NULL) { Py_DECREF(slotnames); diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 0a260f4c10278c..a206bd7b5dd404 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_interpframe.h" // _PyInterpreterFrame #include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK, PyAnnotateFormat +#include "pycore_tuple.h" // _PyTuple_FromPair #include "pycore_typevarobject.h" #include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString() #include "pycore_unionobject.h" // _Py_union_type_or, _Py_union_from_tuple @@ -373,7 +374,7 @@ type_check(PyObject *arg, const char *msg) static PyObject * make_union(PyObject *self, PyObject *other) { - PyObject *args = PyTuple_Pack(2, self, other); + PyObject *args = _PyTuple_FromPair(self, other); if (args == NULL) { return NULL; } From 8a189d819f956071f39696c5d2edbafa69b9ac37 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Tue, 24 Mar 2026 00:23:41 +0500 Subject: [PATCH 02/14] Address review --- Objects/listobject.c | 6 +++--- Objects/stringlib/unicode_format.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 390a5899c42930..761459376522bd 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1437,9 +1437,9 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict) PyObject **dest = self->ob_item + m; Py_ssize_t pos = 0; Py_ssize_t i = 0; - PyObject *key_value[2]; - while (_PyDict_Next((PyObject *)dict, &pos, &key_value[0], &key_value[1], NULL)) { - PyObject *item = _PyTuple_FromPair(key_value[0], key_value[1]); + PyObject *key, *value; + while (_PyDict_Next((PyObject *)dict, &pos, &key, &value, NULL)) { + PyObject *item = _PyTuple_FromPair(key, value); if (item == NULL) { Py_SET_SIZE(self, m + i); return -1; diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h index e591ce50e7d947..22ee6ef5cc328f 100644 --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -1173,7 +1173,7 @@ fieldnameiter_next(PyObject *op) is_attr_obj = PyBool_FromLong(is_attr); if (is_attr_obj == NULL) - goto done; + goto error; /* either an integer or a string */ if (idx != -1) @@ -1181,13 +1181,13 @@ fieldnameiter_next(PyObject *op) else obj = SubString_new_object(&name); if (obj == NULL) - goto done; + goto error; /* return a tuple of values */ result = _PyTuple_FromPairSteal(is_attr_obj, obj); return result; - done: + error: Py_XDECREF(is_attr_obj); Py_XDECREF(obj); return result; @@ -1264,7 +1264,7 @@ formatter_field_name_split(PyObject *Py_UNUSED(module), PyObject *self) first_obj in that case. */ if (!field_name_split((PyObject*)self, 0, PyUnicode_GET_LENGTH(self), &first, &first_idx, &it->it_field, NULL)) - goto done; + goto error; /* first becomes an integer, if possible; else a string */ if (first_idx != -1) @@ -1273,13 +1273,13 @@ formatter_field_name_split(PyObject *Py_UNUSED(module), PyObject *self) /* convert "first" into a string object */ first_obj = SubString_new_object(&first); if (first_obj == NULL) - goto done; + goto error; /* return a tuple of values */ result = _PyTuple_FromPairSteal(first_obj, (PyObject *)it); return result; -done: +error: Py_XDECREF(it); Py_XDECREF(first_obj); return result; From 5c295d35ef7e94954bb16b9b94bafe43708d0cf4 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Tue, 24 Mar 2026 00:27:56 +0500 Subject: [PATCH 03/14] Remove wrong decref --- Objects/dictobject.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 6aedc3f5fe1672..e4ddb61d4984f2 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -6617,7 +6617,6 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) else { Py_INCREF(val1); to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ); - Py_DECREF(val1); if (to_delete < 0) { goto error; } From 5055af7260d9c8564490bbe901ea36d975a69407 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 00:45:51 +0500 Subject: [PATCH 04/14] Apply suggestions from code review Co-authored-by: Victor Stinner --- Objects/enumobject.c | 6 ++---- Objects/floatobject.c | 5 +++-- Objects/longobject.c | 9 +++------ Objects/odictobject.c | 3 +-- Objects/stringlib/unicode_format.h | 6 ++---- 5 files changed, 11 insertions(+), 18 deletions(-) diff --git a/Objects/enumobject.c b/Objects/enumobject.c index d7cad67a0e30a0..597b4c94dbf0d3 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -226,8 +226,7 @@ enum_next_long(enumobject *en, PyObject* next_item) _PyTuple_Recycle(result); return result; } - result = _PyTuple_FromPairSteal(next_index, next_item); - return result; + return _PyTuple_FromPairSteal(next_index, next_item); } static PyObject * @@ -269,8 +268,7 @@ enum_next(PyObject *op) _PyTuple_Recycle(result); return result; } - result = _PyTuple_FromPairSteal(next_index, next_item); - return result; + return _PyTuple_FromPairSteal(next_index, next_item); } static PyObject * diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 33eded3acea321..5504ccface3fe8 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1541,8 +1541,9 @@ float_as_integer_ratio_impl(PyObject *self) goto error; } - result_pair = _PyTuple_FromPairSteal(numerator, denominator); - numerator = denominator = NULL; + Py_DECREF(py_exponent); + + return _PyTuple_FromPairSteal(numerator, denominator); error: Py_XDECREF(py_exponent); diff --git a/Objects/longobject.c b/Objects/longobject.c index 2ca62a92840ab0..f35e1c267f4fbc 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4886,8 +4886,7 @@ long_divmod(PyObject *a, PyObject *b) if (l_divmod((PyLongObject*)a, (PyLongObject*)b, &div, &mod) < 0) { return NULL; } - z = _PyTuple_FromPairSteal((PyObject *)div, (PyObject *)mod); - return z; + return _PyTuple_FromPairSteal((PyObject *)div, (PyObject *)mod); } @@ -6177,8 +6176,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) goto error; } - result = _PyTuple_FromPairSteal((PyObject *)quo, (PyObject *)rem); - return result; + return _PyTuple_FromPairSteal((PyObject *)quo, (PyObject *)rem); error: Py_XDECREF(quo); @@ -6360,8 +6358,7 @@ int_as_integer_ratio_impl(PyObject *self) if (numerator == NULL) { return NULL; } - ratio_tuple = _PyTuple_FromPairSteal(numerator, _PyLong_GetOne()); - return ratio_tuple; + return _PyTuple_FromPairSteal(numerator, _PyLong_GetOne()); } /*[clinic input] diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 786e584a3b83bf..e3dad58a80bd0a 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1171,8 +1171,7 @@ OrderedDict_popitem_impl(PyODictObject *self, int last) value = _odict_popkey_hash((PyObject *)self, key, NULL, _odictnode_HASH(node)); if (value == NULL) return NULL; - item = _PyTuple_FromPairSteal(key, value); - return item; + return _PyTuple_FromPairSteal(key, value); } /* keys() */ diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h index 22ee6ef5cc328f..c9c46283840d18 100644 --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -1184,8 +1184,7 @@ fieldnameiter_next(PyObject *op) goto error; /* return a tuple of values */ - result = _PyTuple_FromPairSteal(is_attr_obj, obj); - return result; + return _PyTuple_FromPairSteal(is_attr_obj, obj); error: Py_XDECREF(is_attr_obj); @@ -1276,8 +1275,7 @@ formatter_field_name_split(PyObject *Py_UNUSED(module), PyObject *self) goto error; /* return a tuple of values */ - result = _PyTuple_FromPairSteal(first_obj, (PyObject *)it); - return result; + return _PyTuple_FromPairSteal(first_obj, (PyObject *)it); error: Py_XDECREF(it); From 0fc920f3683d06690bf3a2fb1091797fd92a8e33 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 01:12:40 +0500 Subject: [PATCH 05/14] Fix warnings --- Objects/longobject.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index f35e1c267f4fbc..f1971f0fca993c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4879,8 +4879,6 @@ static PyObject * long_divmod(PyObject *a, PyObject *b) { PyLongObject *div, *mod; - PyObject *z; - CHECK_BINOP(a, b); if (l_divmod((PyLongObject*)a, (PyLongObject*)b, &div, &mod) < 0) { @@ -6110,7 +6108,7 @@ PyObject * _PyLong_DivmodNear(PyObject *a, PyObject *b) { PyLongObject *quo = NULL, *rem = NULL; - PyObject *twice_rem, *result, *temp; + PyObject *twice_rem, *temp; int quo_is_odd, quo_is_neg; Py_ssize_t cmp; @@ -6353,7 +6351,6 @@ static PyObject * int_as_integer_ratio_impl(PyObject *self) /*[clinic end generated code: output=e60803ae1cc8621a input=384ff1766634bec2]*/ { - PyObject *ratio_tuple; PyObject *numerator = long_long(self); if (numerator == NULL) { return NULL; From 36d7afc3030750f020357cca023ca3bb247439f1 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 01:12:52 +0500 Subject: [PATCH 06/14] Fix memory leaks --- Objects/dictobject.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 1c5348779ea374..43a6884e9065a8 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -6641,6 +6641,8 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) if (_PyDict_DelItem_KnownHash(temp_dict, key, hash) < 0) { goto error; } + Py_DECREF(key); + Py_DECREF(val2); } else { PyObject *pair = _PyTuple_FromPairSteal(key, val2); @@ -6654,6 +6656,7 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) } Py_DECREF(pair); } + Py_XDECREF(val1); } key = val1 = val2 = NULL; From b1c6388090cf754b75f0b1e80bf03276700c3230 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 01:14:03 +0500 Subject: [PATCH 07/14] Rename error label --- Objects/odictobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/odictobject.c b/Objects/odictobject.c index e3dad58a80bd0a..c2b5e60c702cfa 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1804,7 +1804,7 @@ odictiter_iternext_lock_held(PyObject *op) if (!PyErr_Occurred()) PyErr_SetObject(PyExc_KeyError, key); Py_DECREF(key); - goto done; + goto error; } /* Handle the values case. */ @@ -1831,13 +1831,13 @@ odictiter_iternext_lock_held(PyObject *op) else { result = _PyTuple_FromPairSteal(key, value); if (result == NULL) { - goto done; + goto error; } } return result; -done: +error: Py_CLEAR(di->di_current); Py_CLEAR(di->di_odict); return NULL; From a649f9e0b2bd2e79a987d85eb526bbf4a8ef8db2 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 01:23:11 +0500 Subject: [PATCH 08/14] Added error label --- Objects/frameobject.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index c4beb3f106ea3a..d995b004a6f0c6 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -633,17 +633,14 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored)) if (value) { PyObject *pair = _PyTuple_FromPairSteal(Py_NewRef(name), value); if (pair == NULL) { - Py_DECREF(items); - return NULL; - } - - if (PyList_Append(items, pair) < 0) { - Py_DECREF(items); - Py_DECREF(pair); - return NULL; + goto error; } + int rc = PyList_Append(items, pair); Py_DECREF(pair); + if (rc < 0) { + goto error; + } } } @@ -655,21 +652,21 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored)) while (PyDict_Next(frame->f_extra_locals, &j, &key, &value)) { PyObject *pair = _PyTuple_FromPair(key, value); if (pair == NULL) { - Py_DECREF(items); - return NULL; - } - - if (PyList_Append(items, pair) < 0) { - Py_DECREF(items); - Py_DECREF(pair); - return NULL; + goto error; } + int rc = PyList_Append(items, pair); Py_DECREF(pair); + if (rc < 0) { + goto error; + } } } return items; +error: + Py_DECREF(items); + return NULL; } static Py_ssize_t From 83cc58283cf5dd564b846d2929ccc5d810764a92 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 01:37:35 +0500 Subject: [PATCH 09/14] Remove unused variable --- Objects/odictobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/odictobject.c b/Objects/odictobject.c index c2b5e60c702cfa..a330c11a4eb1ff 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1156,7 +1156,7 @@ static PyObject * OrderedDict_popitem_impl(PyODictObject *self, int last) /*[clinic end generated code: output=98e7d986690d49eb input=8aafc7433e0a40e7]*/ { - PyObject *key, *value, *item = NULL; + PyObject *key, *value; _ODictNode *node; /* pull the item */ From 5db192253d1d8f898053538bfbeab0e345f4df3b Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 01:37:58 +0500 Subject: [PATCH 10/14] Fix possible memory leak --- Objects/odictobject.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Objects/odictobject.c b/Objects/odictobject.c index a330c11a4eb1ff..e3ec0ae470c5d8 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1169,8 +1169,10 @@ OrderedDict_popitem_impl(PyODictObject *self, int last) node = last ? _odict_LAST(self) : _odict_FIRST(self); key = Py_NewRef(_odictnode_KEY(node)); value = _odict_popkey_hash((PyObject *)self, key, NULL, _odictnode_HASH(node)); - if (value == NULL) + if (value == NULL) { + Py_DECREF(key); return NULL; + } return _PyTuple_FromPairSteal(key, value); } From 0b035373f3732ccb25f5d2a30b699136d978b519 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 02:07:59 +0500 Subject: [PATCH 11/14] Apply suggestions from code review Co-authored-by: Victor Stinner --- Objects/dictobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 43a6884e9065a8..fa1ad036875987 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -6641,8 +6641,8 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) if (_PyDict_DelItem_KnownHash(temp_dict, key, hash) < 0) { goto error; } - Py_DECREF(key); - Py_DECREF(val2); + Py_CLEAR(key); + Py_CLEAR(val2); } else { PyObject *pair = _PyTuple_FromPairSteal(key, val2); @@ -6656,7 +6656,7 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) } Py_DECREF(pair); } - Py_XDECREF(val1); + Py_CLEAR(val1); } key = val1 = val2 = NULL; From 7ed7b94af66c829d93cfecc225bd568ce598a036 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 02:09:34 +0500 Subject: [PATCH 12/14] Address review --- Objects/floatobject.c | 1 - Objects/frameobject.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 5504ccface3fe8..d91468dddded9b 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1540,7 +1540,6 @@ float_as_integer_ratio_impl(PyObject *self) if (denominator == NULL) goto error; } - Py_DECREF(py_exponent); return _PyTuple_FromPairSteal(numerator, denominator); diff --git a/Objects/frameobject.c b/Objects/frameobject.c index d995b004a6f0c6..5ae85c5bca61b9 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -664,6 +664,7 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored)) } return items; + error: Py_DECREF(items); return NULL; From 1b4df92571066a23bdda6cf024ec170547669b05 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 02:09:54 +0500 Subject: [PATCH 13/14] Variables already null after while loop --- Objects/dictobject.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index fa1ad036875987..3d2a56adb73e46 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -6658,7 +6658,6 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) } Py_CLEAR(val1); } - key = val1 = val2 = NULL; PyObject *remaining_pairs = PyObject_CallMethodNoArgs( temp_dict, &_Py_ID(items)); From 06a01eb1827dcd3f31094271382ae2cd1b7b1f32 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Sat, 28 Mar 2026 02:26:06 +0500 Subject: [PATCH 14/14] Address review --- Objects/dictobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 3d2a56adb73e46..a6c40454d52a71 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -6632,17 +6632,18 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) else { Py_INCREF(val1); to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ); + Py_CLEAR(val1); if (to_delete < 0) { goto error; } } if (to_delete) { + Py_CLEAR(val2); if (_PyDict_DelItem_KnownHash(temp_dict, key, hash) < 0) { goto error; } Py_CLEAR(key); - Py_CLEAR(val2); } else { PyObject *pair = _PyTuple_FromPairSteal(key, val2); @@ -6656,7 +6657,6 @@ dictitems_xor_lock_held(PyObject *d1, PyObject *d2) } Py_DECREF(pair); } - Py_CLEAR(val1); } PyObject *remaining_pairs = PyObject_CallMethodNoArgs(