bpo-36218: Fix handling of heterogeneous values in list.sort (GH-12209) · python/cpython@dd5417a (original) (raw)

3 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -373,6 +373,11 @@ def test_unsafe_tuple_compare(self):
373 373 check_against_PyObject_RichCompareBool(self, [float('nan')]*100)
374 374 check_against_PyObject_RichCompareBool(self, [float('nan') for
375 375 _ in range(100)])
376 +
377 +def test_not_all_tuples(self):
378 +self.assertRaises(TypeError, [(1.0, 1.0), (False, "A"), 6].sort)
379 +self.assertRaises(TypeError, [('a', 1), (1, 'a')].sort)
380 +self.assertRaises(TypeError, [(1, 'a'), ('a', 1)].sort)
376 381 #==============================================================================
377 382
378 383 if __name__ == "__main__":
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1 +Fix a segfault occuring when sorting a list of heterogeneous values. Patch
2 +contributed by Rémi Lapeyre and Elliot Gorokhovsky.
Original file line number Diff line number Diff line change
@@ -2306,19 +2306,28 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
2306 2306
2307 2307 if (key->ob_type != key_type) {
2308 2308 keys_are_all_same_type = 0;
2309 -break;
2309 +/* If keys are in tuple we must loop over the whole list to make
2310 + sure all items are tuples */
2311 +if (!keys_are_in_tuples) {
2312 +break;
2313 + }
2310 2314 }
2311 2315
2312 -if (key_type == &PyLong_Type) {
2313 -if (ints_are_bounded && Py_ABS(Py_SIZE(key)) > 1)
2316 +if (keys_are_all_same_type) {
2317 +if (key_type == &PyLong_Type &&
2318 +ints_are_bounded &&
2319 +Py_ABS(Py_SIZE(key)) > 1) {
2320 +
2314 2321 ints_are_bounded = 0;
2322 + }
2323 +else if (key_type == &PyUnicode_Type &&
2324 +strings_are_latin &&
2325 +PyUnicode_KIND(key) != PyUnicode_1BYTE_KIND) {
2326 +
2327 +strings_are_latin = 0;
2328 + }
2329 + }
2315 2330 }
2316 -else if (key_type == &PyUnicode_Type){
2317 -if (strings_are_latin &&
2318 -PyUnicode_KIND(key) != PyUnicode_1BYTE_KIND)
2319 -strings_are_latin = 0;
2320 - }
2321 - }
2322 2331
2323 2332 /* Choose the best compare, given what we now know about the keys. */
2324 2333 if (keys_are_all_same_type) {
@@ -2346,10 +2355,12 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
2346 2355 if (keys_are_in_tuples) {
2347 2356 /* Make sure we're not dealing with tuples of tuples
2348 2357 * (remember: here, key_type refers list [key[0] for key in keys]) */
2349 -if (key_type == &PyTuple_Type)
2358 +if (key_type == &PyTuple_Type) {
2350 2359 ms.tuple_elem_compare = safe_object_compare;
2351 -else
2360 + }
2361 +else {
2352 2362 ms.tuple_elem_compare = ms.key_compare;
2363 + }
2353 2364
2354 2365 ms.key_compare = unsafe_tuple_compare;
2355 2366 }