Skip to content

Commit 9718f66

Browse files
committed
fixup! bpo-39421: Fix posible crash in heapq with custom comparison operators
1 parent d026117 commit 9718f66

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

‎Lib/test/test_heapq.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,25 @@ def __lt__(self, o):
444444
self.module.heappush(heap, EvilClass(0))
445445
self.assertRaises(IndexError, self.module.heappushpop, heap, 1)
446446

447+
def test_comparison_operator_modifiying_heap_two_heaps(self):
448+
449+
class h(int):
450+
def __lt__(self, o):
451+
list2.clear()
452+
return NotImplemented
453+
454+
class g(int):
455+
def __lt__(self, o):
456+
list1.clear()
457+
return NotImplemented
458+
459+
list1, list2 = [], []
460+
461+
self.module.heappush(list1, h(0))
462+
self.module.heappush(list2, g(0))
463+
464+
self.assertRaises((IndexError, RuntimeError), self.module.heappush, list1, g(1))
465+
self.assertRaises((IndexError, RuntimeError), self.module.heappush, list2, h(1))
447466

448467
class TestErrorHandlingPython(TestErrorHandling, TestCase):
449468
module = py_heapq

‎Modules/_heapqmodule.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
3636
while (pos > startpos) {
3737
parentpos = (pos - 1) >> 1;
3838
parent = arr[parentpos];
39+
Py_INCREF(newitem);
40+
Py_INCREF(parent);
3941
cmp = PyObject_RichCompareBool(newitem, parent, Py_LT);
42+
Py_DECREF(parent);
43+
Py_DECREF(newitem);
4044
if (cmp < 0)
4145
return -1;
4246
if (size != PyList_GET_SIZE(heap)) {

0 commit comments

Comments
 (0)