GH-145247: Use _PyTuple_FromPair[Steal] in Objects#145884
GH-145247: Use _PyTuple_FromPair[Steal] in Objects#145884sergey-miryanov wants to merge 5 commits intopython:mainfrom
Conversation
Objects/stringlib/unicode_format.h
Outdated
| result = _PyTuple_FromPairSteal(is_attr_obj, obj); | ||
| return result; | ||
|
|
||
| done: |
Objects/stringlib/unicode_format.h
Outdated
| result = _PyTuple_FromPairSteal(first_obj, (PyObject *)it); | ||
| return result; | ||
|
|
||
| done: |
| to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ); | ||
| Py_DECREF(val1); | ||
| if (to_delete < 0) { | ||
| goto error; |
There was a problem hiding this comment.
Is this safe? If goto error happens, won't it decref twice?
There was a problem hiding this comment.
You are right, it is not safe. I don't understand why I did this (blame on me).
Objects/listobject.c
Outdated
| @@ -1439,7 +1439,7 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict) | |||
| Py_ssize_t i = 0; | |||
| PyObject *key_value[2]; | |||
sergey-miryanov
left a comment
There was a problem hiding this comment.
Address review
Objects/stringlib/unicode_format.h
Outdated
| result = _PyTuple_FromPairSteal(is_attr_obj, obj); | ||
| return result; | ||
|
|
||
| done: |
Objects/stringlib/unicode_format.h
Outdated
| result = _PyTuple_FromPairSteal(first_obj, (PyObject *)it); | ||
| return result; | ||
|
|
||
| done: |
Objects/listobject.c
Outdated
| @@ -1439,7 +1439,7 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict) | |||
| Py_ssize_t i = 0; | |||
| PyObject *key_value[2]; | |||
…ey-miryanov/cpython into feat/145247-pytuple-from-pair-use-2
vstinner
left a comment
There was a problem hiding this comment.
This change introduces a leak in the dict type (see my comment below about a leak).
| result = _PyTuple_FromPairSteal(is_attr_obj, obj); | ||
| return result; |
There was a problem hiding this comment.
Please remove the result variable in this scope and replace return result with return NULL in the error path. By the way, previously this function had two result variables!
| result = _PyTuple_FromPairSteal(is_attr_obj, obj); | |
| return result; | |
| return _PyTuple_FromPairSteal(is_attr_obj, obj); |
| result = _PyTuple_FromPairSteal(first_obj, (PyObject *)it); | ||
| return result; |
There was a problem hiding this comment.
Same remark, you can now remove the result variable to simplify the code.
| result = _PyTuple_FromPairSteal(first_obj, (PyObject *)it); | |
| return result; | |
| return _PyTuple_FromPairSteal(first_obj, (PyObject *)it); |
| Py_DECREF(pair); | ||
| } | ||
| Py_DECREF(key); | ||
| Py_XDECREF(val1); |
There was a problem hiding this comment.
This removal is suspicious, since there is still Py_INCREF(val1); above.
The problem is that test_dict uses many immortal objects, so they can fail to detect refleaks.
With this patch, I can trigger a leak using ./python -m test -v test_dict -m test_dictview_set_operations_on_items -R 3:3:
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index b2f4363b23e..4f2b6e1dc14 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -804,6 +804,11 @@ def test_dictview_set_operations_on_items(self):
self.assertEqual(k1 ^ k2, {(3,3)})
self.assertEqual(k1 ^ k3, {(1,1), (2,2), (4,4)})
+ obj = object()
+ d = {obj: b'abc'.decode()}.items()
+ d2 = {obj: b'def'.decode()}.items()
+ d ^ d2
+
def test_items_symmetric_difference(self):
rr = random.randrange
for _ in range(100):| result = _PyTuple_FromPairSteal(next_index, next_item); | ||
| return result; |
There was a problem hiding this comment.
| result = _PyTuple_FromPairSteal(next_index, next_item); | |
| return result; | |
| return _PyTuple_FromPairSteal(next_index, next_item); |
| result = _PyTuple_FromPairSteal(next_index, next_item); | ||
| return result; |
There was a problem hiding this comment.
| result = _PyTuple_FromPairSteal(next_index, next_item); | |
| return result; | |
| return _PyTuple_FromPairSteal(next_index, next_item); |
| z = _PyTuple_FromPairSteal((PyObject *)div, (PyObject *)mod); | ||
| return z; |
There was a problem hiding this comment.
| z = _PyTuple_FromPairSteal((PyObject *)div, (PyObject *)mod); | |
| return z; | |
| return _PyTuple_FromPairSteal((PyObject *)div, (PyObject *)mod); |
The z variable is no longer needed.
| result = _PyTuple_FromPairSteal((PyObject *)quo, (PyObject *)rem); | ||
| return result; |
There was a problem hiding this comment.
| result = _PyTuple_FromPairSteal((PyObject *)quo, (PyObject *)rem); | |
| return result; | |
| return _PyTuple_FromPairSteal((PyObject *)quo, (PyObject *)rem); |
| ratio_tuple = _PyTuple_FromPairSteal(numerator, _PyLong_GetOne()); | ||
| return ratio_tuple; |
There was a problem hiding this comment.
| ratio_tuple = _PyTuple_FromPairSteal(numerator, _PyLong_GetOne()); | |
| return ratio_tuple; | |
| return _PyTuple_FromPairSteal(numerator, _PyLong_GetOne()); |
| item = _PyTuple_FromPairSteal(key, value); | ||
| return item; |
There was a problem hiding this comment.
| item = _PyTuple_FromPairSteal(key, value); | |
| return item; | |
| return _PyTuple_FromPairSteal(key, value); |
| if (result == NULL) { | ||
| Py_DECREF(key); | ||
| Py_DECREF(value); | ||
| goto done; |
There was a problem hiding this comment.
It's strange to call this label "done" whereas it's only used for error path. It should be called "error".
It is a second PR for usage of _PyTuple_FromPair[Steal] in the codebase.
PyTuple_FromPair#145247