Skip to content

Commit 2ee8791

Browse files
corona10methane
authored andcommitted
[3.8] bpo-38588: Fix possible crashes in dict and list when calling P… (GH-17764)
* [3.8] 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]> * Update Objects/listobject.c @methane's suggestion Co-Authored-By: Inada Naoki <[email protected]> Co-authored-by: Inada Naoki <[email protected]>
1 parent a278ae1 commit 2ee8791

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
@@ -1221,7 +1221,7 @@ def test_free_after_iterating(self):
12211221
support.check_free_after_iterating(self, lambda d: iter(d.items()), dict)
12221222

12231223
def test_equal_operator_modifying_operand(self):
1224-
# test fix for seg fault reported in issue 27945 part 3.
1224+
# test fix for seg fault reported in bpo-27945 part 3.
12251225
class X():
12261226
def __del__(self):
12271227
dict_b.clear()
@@ -1237,6 +1237,16 @@ def __hash__(self):
12371237
dict_b = {X(): X()}
12381238
self.assertTrue(dict_a == dict_b)
12391239

1240+
# test fix for seg fault reported in bpo-38588 part 1.
1241+
class Y:
1242+
def __eq__(self, other):
1243+
dict_d.clear()
1244+
return True
1245+
1246+
dict_c = {0: Y()}
1247+
dict_d = {0: set()}
1248+
self.assertTrue(dict_c == dict_d)
1249+
12401250
def test_fromkeys_operator_modifying_dict_operand(self):
12411251
# test fix for seg fault reported in issue 27945 part 4a.
12421252
class X(int):

Lib/test/test_list.py

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

161+
def test_equal_operator_modifying_operand(self):
162+
# test fix for seg fault reported in bpo-38588 part 2.
163+
class X:
164+
def __eq__(self,other) :
165+
list2.clear()
166+
return NotImplemented
167+
168+
class Y:
169+
def __eq__(self, other):
170+
list1.clear()
171+
return NotImplemented
172+
173+
class Z:
174+
def __eq__(self, other):
175+
list3.clear()
176+
return NotImplemented
177+
178+
list1 = [X()]
179+
list2 = [Y()]
180+
self.assertTrue(list1 == list2)
181+
182+
list3 = [Z()]
183+
list4 = [1]
184+
self.assertFalse(list3 == list4)
185+
161186
@cpython_only
162187
def test_preallocation(self):
163188
iterable = [0] * 10
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
@@ -2773,9 +2773,11 @@ dict_equal(PyDictObject *a, PyDictObject *b)
27732773
return -1;
27742774
return 0;
27752775
}
2776+
Py_INCREF(bval);
27762777
cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
27772778
Py_DECREF(key);
27782779
Py_DECREF(aval);
2780+
Py_DECREF(bval);
27792781
if (cmp <= 0) /* error or not equal */
27802782
return cmp;
27812783
}

Objects/listobject.c

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

26652665
/* Search for the first index where items are different */
26662666
for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
2667+
PyObject *vitem = vl->ob_item[i];
2668+
PyObject *witem = wl->ob_item[i];
2669+
if (vitem == witem) {
2670+
continue;
2671+
}
2672+
2673+
Py_INCREF(vitem);
2674+
Py_INCREF(witem);
26672675
int k = PyObject_RichCompareBool(vl->ob_item[i],
26682676
wl->ob_item[i], Py_EQ);
2677+
Py_DECREF(vitem);
2678+
Py_DECREF(witem);
26692679
if (k < 0)
26702680
return NULL;
26712681
if (!k)

0 commit comments

Comments
 (0)