summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDong-hee Na <donghee.na92@gmail.com>2019-12-31 13:15:10 +0900
committerPablo Galindo <Pablogsal@gmail.com>2019-12-31 04:15:10 +0000
commit53f11ba7b1498133ce3ff8173d5ae2e0182a3603 (patch)
tree32daa851e500ec9d53613c4876034b20a89d3a10
parentc9c17cc933dcffb9ed7f03e3f791d8cfd7acc54a (diff)
downloadcpython-git-53f11ba7b1498133ce3ff8173d5ae2e0182a3603.tar.gz
[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 2d5bf568eaa5059402ccce9ba5a366986ba27c8a) Co-authored-by: Dong-hee Na <donghee.na92@gmail.com> * methane's suggestion methane's suggestion Co-Authored-By: Inada Naoki <songofacandy@gmail.com> Co-authored-by: Inada Naoki <songofacandy@gmail.com>
-rw-r--r--Lib/test/test_dict.py12
-rw-r--r--Lib/test/test_list.py25
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2019-12-29-19-13-54.bpo-38588.pgXnNS.rst2
-rw-r--r--Objects/dictobject.c2
-rw-r--r--Objects/listobject.c10
5 files changed, 50 insertions, 1 deletions
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 90c0a3131a..ea9dcb6a81 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -1138,7 +1138,7 @@ class DictTest(unittest.TestCase):
support.check_free_after_iterating(self, lambda d: iter(d.items()), dict)
def test_equal_operator_modifying_operand(self):
- # test fix for seg fault reported in issue 27945 part 3.
+ # test fix for seg fault reported in bpo-27945 part 3.
class X():
def __del__(self):
dict_b.clear()
@@ -1154,6 +1154,16 @@ class DictTest(unittest.TestCase):
dict_b = {X(): X()}
self.assertTrue(dict_a == dict_b)
+ # test fix for seg fault reported in bpo-38588 part 1.
+ class Y:
+ def __eq__(self, other):
+ dict_d.clear()
+ return True
+
+ dict_c = {0: Y()}
+ dict_d = {0: set()}
+ self.assertTrue(dict_c == dict_d)
+
def test_fromkeys_operator_modifying_dict_operand(self):
# test fix for seg fault reported in issue 27945 part 4a.
class X(int):
diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py
index ece4598e4e..553ac8c1ce 100644
--- a/Lib/test/test_list.py
+++ b/Lib/test/test_list.py
@@ -162,6 +162,31 @@ class ListTest(list_tests.CommonTest):
with self.assertRaises(TypeError):
(3,) + L([1,2])
+ def test_equal_operator_modifying_operand(self):
+ # test fix for seg fault reported in bpo-38588 part 2.
+ class X:
+ def __eq__(self,other) :
+ list2.clear()
+ return NotImplemented
+
+ class Y:
+ def __eq__(self, other):
+ list1.clear()
+ return NotImplemented
+
+ class Z:
+ def __eq__(self, other):
+ list3.clear()
+ return NotImplemented
+
+ list1 = [X()]
+ list2 = [Y()]
+ self.assertTrue(list1 == list2)
+
+ list3 = [Z()]
+ list4 = [1]
+ self.assertFalse(list3 == list4)
+
def test_count_index_remove_crashes(self):
# bpo-38610: The count(), index(), and remove() methods were not
# holding strong references to list elements while calling
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-12-29-19-13-54.bpo-38588.pgXnNS.rst b/Misc/NEWS.d/next/Core and Builtins/2019-12-29-19-13-54.bpo-38588.pgXnNS.rst
new file mode 100644
index 0000000000..0b81085a89
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-12-29-19-13-54.bpo-38588.pgXnNS.rst
@@ -0,0 +1,2 @@
+Fix possible crashes in dict and list when calling
+:c:func:`PyObject_RichCompareBool`.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 9437448849..3f00002a89 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2677,9 +2677,11 @@ dict_equal(PyDictObject *a, PyDictObject *b)
return -1;
return 0;
}
+ Py_INCREF(bval);
cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
Py_DECREF(key);
Py_DECREF(aval);
+ Py_DECREF(bval);
if (cmp <= 0) /* error or not equal */
return cmp;
}
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 724f25677a..d622da9e0d 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -2615,8 +2615,18 @@ list_richcompare(PyObject *v, PyObject *w, int op)
/* Search for the first index where items are different */
for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
+ PyObject *vitem = vl->ob_item[i];
+ PyObject *witem = wl->ob_item[i];
+ if (vitem == witem) {
+ continue;
+ }
+
+ Py_INCREF(vitem);
+ Py_INCREF(witem);
int k = PyObject_RichCompareBool(vl->ob_item[i],
wl->ob_item[i], Py_EQ);
+ Py_DECREF(vitem);
+ Py_DECREF(witem);
if (k < 0)
return NULL;
if (!k)