Skip to content

Commit 8447fa6

Browse files
fix: eliminate race condition in list rich comparison
1 parent 72eca2a commit 8447fa6

1 file changed

Lines changed: 29 additions & 15 deletions

File tree

Objects/listobject.c

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3432,44 +3432,58 @@ list_richcompare_impl(PyObject *v, PyObject *w, int op)
34323432
Py_RETURN_TRUE;
34333433
}
34343434

3435-
/* Search for the first index where items are different */
3435+
/* Search for the first index where items are different.
3436+
* Keep vitem/witem alive across the break so that the final ordering
3437+
* comparison uses the same differing objects.
3438+
* This is required as PyObject_RichCompareBool may release the GIL and
3439+
* the list may be mutated in the meantime.
3440+
*/
3441+
PyObject *vitem = NULL;
3442+
PyObject *witem = NULL;
34363443
for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
3437-
PyObject *vitem = vl->ob_item[i];
3438-
PyObject *witem = wl->ob_item[i];
3444+
vitem = vl->ob_item[i];
3445+
witem = wl->ob_item[i];
34393446
if (vitem == witem) {
34403447
continue;
34413448
}
34423449

34433450
Py_INCREF(vitem);
34443451
Py_INCREF(witem);
34453452
int k = PyObject_RichCompareBool(vitem, witem, Py_EQ);
3446-
Py_DECREF(vitem);
3447-
Py_DECREF(witem);
3448-
if (k < 0)
3453+
if (k < 0) {
3454+
Py_DECREF(vitem);
3455+
Py_DECREF(witem);
34493456
return NULL;
3450-
if (!k)
3457+
}
3458+
if (!k) {
3459+
/* keep vitem/witem alive for the final comparison */
34513460
break;
3461+
}
3462+
3463+
Py_DECREF(vitem);
3464+
Py_DECREF(witem);
3465+
vitem = witem = NULL;
34523466
}
34533467

3454-
if (i >= Py_SIZE(vl) || i >= Py_SIZE(wl)) {
3455-
/* No more items to compare -- compare sizes */
3468+
if (vitem == NULL) {
3469+
/* All compared elements were equal -- compare sizes */
34563470
Py_RETURN_RICHCOMPARE(Py_SIZE(vl), Py_SIZE(wl), op);
34573471
}
34583472

34593473
/* We have an item that differs -- shortcuts for EQ/NE */
34603474
if (op == Py_EQ) {
3475+
Py_DECREF(vitem);
3476+
Py_DECREF(witem);
34613477
Py_RETURN_FALSE;
34623478
}
34633479
if (op == Py_NE) {
3480+
Py_DECREF(vitem);
3481+
Py_DECREF(witem);
34643482
Py_RETURN_TRUE;
34653483
}
34663484

3467-
/* Compare the final item again using the proper operator */
3468-
PyObject *vitem = vl->ob_item[i];
3469-
PyObject *witem = wl->ob_item[i];
3470-
Py_INCREF(vitem);
3471-
Py_INCREF(witem);
3472-
PyObject *result = PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
3485+
/* Compare the differing items using the proper operator */
3486+
PyObject *result = PyObject_RichCompare(vitem, witem, op);
34733487
Py_DECREF(vitem);
34743488
Py_DECREF(witem);
34753489
return result;

0 commit comments

Comments
 (0)