]> granicus.if.org Git - python/commitdiff
bpo-36218: Fix handling of heterogeneous values in list.sort (GH-12209)
authorRémi Lapeyre <remi.lapeyre@henki.fr>
Mon, 25 Mar 2019 07:25:37 +0000 (08:25 +0100)
committerRaymond Hettinger <rhettinger@users.noreply.github.com>
Mon, 25 Mar 2019 07:25:37 +0000 (00:25 -0700)
Lib/test/test_sort.py
Misc/NEWS.d/next/Core and Builtins/2019-03-07-13-05-43.bpo-36218.dZemNt.rst [new file with mode: 0644]
Objects/listobject.c

index f2f53cb1a72f6397b48d22c35c4d22cec40137f6..41de4b684f62513e1e30f4ef59e99f5f8405981d 100644 (file)
@@ -373,6 +373,11 @@ class TestOptimizedCompares(unittest.TestCase):
         check_against_PyObject_RichCompareBool(self, [float('nan')]*100)
         check_against_PyObject_RichCompareBool(self, [float('nan') for
                                                       _ in range(100)])
+
+    def test_not_all_tuples(self):
+        self.assertRaises(TypeError, [(1.0, 1.0), (False, "A"), 6].sort)
+        self.assertRaises(TypeError, [('a', 1), (1, 'a')].sort)
+        self.assertRaises(TypeError, [(1, 'a'), ('a', 1)].sort)
 #==============================================================================
 
 if __name__ == "__main__":
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-03-07-13-05-43.bpo-36218.dZemNt.rst b/Misc/NEWS.d/next/Core and Builtins/2019-03-07-13-05-43.bpo-36218.dZemNt.rst
new file mode 100644 (file)
index 0000000..ab6d207
--- /dev/null
@@ -0,0 +1,2 @@
+Fix a segfault occuring when sorting a list of heterogeneous values. Patch
+contributed by Rémi Lapeyre and Elliot Gorokhovsky.
\ No newline at end of file
index b6524e8bd7fc5de2aa37a2e6175cf5fb7c40c899..c29954283c488ea777f4a8abe1c6a2b46a6c370d 100644 (file)
@@ -2306,19 +2306,28 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
 
             if (key->ob_type != key_type) {
                 keys_are_all_same_type = 0;
-                break;
+                /* If keys are in tuple we must loop over the whole list to make
+                   sure all items are tuples */
+                if (!keys_are_in_tuples) {
+                    break;
+                }
             }
 
-            if (key_type == &PyLong_Type) {
-                if (ints_are_bounded && Py_ABS(Py_SIZE(key)) > 1)
+            if (keys_are_all_same_type) {
+                if (key_type == &PyLong_Type &&
+                    ints_are_bounded &&
+                    Py_ABS(Py_SIZE(key)) > 1) {
+
                     ints_are_bounded = 0;
+                }
+                else if (key_type == &PyUnicode_Type &&
+                         strings_are_latin &&
+                         PyUnicode_KIND(key) != PyUnicode_1BYTE_KIND) {
+
+                        strings_are_latin = 0;
+                    }
+                }
             }
-            else if (key_type == &PyUnicode_Type){
-                if (strings_are_latin &&
-                    PyUnicode_KIND(key) != PyUnicode_1BYTE_KIND)
-                strings_are_latin = 0;
-            }
-        }
 
         /* Choose the best compare, given what we now know about the keys. */
         if (keys_are_all_same_type) {
@@ -2346,10 +2355,12 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
         if (keys_are_in_tuples) {
             /* Make sure we're not dealing with tuples of tuples
              * (remember: here, key_type refers list [key[0] for key in keys]) */
-            if (key_type == &PyTuple_Type)
+            if (key_type == &PyTuple_Type) {
                 ms.tuple_elem_compare = safe_object_compare;
-            else
+            }
+            else {
                 ms.tuple_elem_compare = ms.key_compare;
+            }
 
             ms.key_compare = unsafe_tuple_compare;
         }