Skip to content

Commit 53f11ba

Browse files
corona10methane
authored andcommitted
[3.7] bpo-38588: Fix possible crashes in dict and list when calling P… (GH-17765)
* [3.7] bpo-38588: Fix possible crashes in dict and list when calling PyObject_RichCompareBool (GH-17734) Take strong references before calling PyObject_RichCompareBool to protect against the case where the object dies during the call.. (cherry picked from commit 2d5bf56) Co-authored-by: Dong-hee Na <[email protected]> * methane's suggestion methane's suggestion Co-Authored-By: Inada Naoki <[email protected]> Co-authored-by: Inada Naoki <[email protected]>
1 parent c9c17cc commit 53f11ba

File tree

5 files changed

+50
-1
lines changed

5 files changed

+50
-1
lines changed

Lib/test/test_dict.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@ def test_free_after_iterating(self):
11381138
support.check_free_after_iterating(self, lambda d: iter(d.items()), dict)
11391139

11401140
def test_equal_operator_modifying_operand(self):
1141-
# test fix for seg fault reported in issue 27945 part 3.
1141+
# test fix for seg fault reported in bpo-27945 part 3.
11421142
class X():
11431143
def __del__(self):
11441144
dict_b.clear()
@@ -1154,6 +1154,16 @@ def __hash__(self):
11541154
dict_b = {X(): X()}
11551155
self.assertTrue(dict_a == dict_b)
11561156

1157+
# test fix for seg fault reported in bpo-38588 part 1.
1158+
class Y:
1159+
def __eq__(self, other):
1160+
dict_d.clear()
1161+
return True
1162+
1163+
dict_c = {0: Y()}
1164+
dict_d = {0: set()}
1165+
self.assertTrue(dict_c == dict_d)
1166+
11571167
def test_fromkeys_operator_modifying_dict_operand(self):
11581168
# test fix for seg fault reported in issue 27945 part 4a.
11591169
class X(int):

Lib/test/test_list.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,31 @@ class L(list): pass
162162
with self.assertRaises(TypeError):
163163
(3,) + L([1,2])
164164

165+
def test_equal_operator_modifying_operand(self):
166+
# test fix for seg fault reported in bpo-38588 part 2.
167+
class X:
168+
def __eq__(self,other) :
169+
list2.clear()
170+
return NotImplemented
171+
172+
class Y:
173+
def __eq__(self, other):
174+
list1.clear()
175+
return NotImplemented
176+
177+
class Z:
178+
def __eq__(self, other):
179+
list3.clear()
180+
return NotImplemented
181+
182+
list1 = [X()]
183+
list2 = [Y()]
184+
self.assertTrue(list1 == list2)
185+
186+
list3 = [Z()]
187+
list4 = [1]
188+
self.assertFalse(list3 == list4)
189+
165190
def test_count_index_remove_crashes(self):
166191
# bpo-38610: The count(), index(), and remove() methods were not
167192
# holding strong references to list elements while calling
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix possible crashes in dict and list when calling
2+
:c:func:`PyObject_RichCompareBool`.

Objects/dictobject.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2677,9 +2677,11 @@ dict_equal(PyDictObject *a, PyDictObject *b)
26772677
return -1;
26782678
return 0;
26792679
}
2680+
Py_INCREF(bval);
26802681
cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
26812682
Py_DECREF(key);
26822683
Py_DECREF(aval);
2684+
Py_DECREF(bval);
26832685
if (cmp <= 0) /* error or not equal */
26842686
return cmp;
26852687
}

Objects/listobject.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2615,8 +2615,18 @@ list_richcompare(PyObject *v, PyObject *w, int op)
26152615

26162616
/* Search for the first index where items are different */
26172617
for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
2618+
PyObject *vitem = vl->ob_item[i];
2619+
PyObject *witem = wl->ob_item[i];
2620+
if (vitem == witem) {
2621+
continue;
2622+
}
2623+
2624+
Py_INCREF(vitem);
2625+
Py_INCREF(witem);
26182626
int k = PyObject_RichCompareBool(vl->ob_item[i],
26192627
wl->ob_item[i], Py_EQ);
2628+
Py_DECREF(vitem);
2629+
Py_DECREF(witem);
26202630
if (k < 0)
26212631
return NULL;
26222632
if (!k)

0 commit comments

Comments
 (0)