]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.7] bpo-38588: Fix possible crashes in dict and list when calling P… (GH-17765)
authorDong-hee Na <donghee.na92@gmail.com>
Tue, 31 Dec 2019 04:15:10 +0000 (13:15 +0900)
committerPablo Galindo <Pablogsal@gmail.com>
Tue, 31 Dec 2019 04:15:10 +0000 (04:15 +0000)
* [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>
Lib/test/test_dict.py
Lib/test/test_list.py
Misc/NEWS.d/next/Core and Builtins/2019-12-29-19-13-54.bpo-38588.pgXnNS.rst [new file with mode: 0644]
Objects/dictobject.c
Objects/listobject.c

index 90c0a3131a78eb1b92934bfdabc8c6dfadeb922a..ea9dcb6a81c6a668603b0705e5aa1ab0382e6110 100644 (file)
@@ -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):
index ece4598e4eaf23c027ae7776c668bbbba59ef240..553ac8c1cef81137f43f5496a15d135e84f21d76 100644 (file)
@@ -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 (file)
index 0000000..0b81085
--- /dev/null
@@ -0,0 +1,2 @@
+Fix possible crashes in dict and list when calling
+:c:func:`PyObject_RichCompareBool`.
index 94374488490073f700341d4ac4095dd23c23a265..3f00002a8991ae39d3feec42867a3de4e665cbcb 100644 (file)
@@ -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;
         }
index 724f25677a16e1840f1eb6473f1d617424510f56..d622da9e0dbf337cf7c25dffbd9c178bcc1d5f4e 100644 (file)
@@ -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)