gh-119004: fix a crash in equality testing between OrderedDict (#121329)

This commit is contained in:
Bénédikt Tran 2024-09-24 01:44:36 +02:00 committed by GitHub
parent e80dd3035f
commit 38a887dc3e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 145 additions and 11 deletions

View file

@ -796,6 +796,7 @@ _odict_clear_nodes(PyODictObject *od)
_odictnode_DEALLOC(node);
node = next;
}
od->od_state++;
}
/* There isn't any memory management of nodes past this point. */
@ -806,24 +807,40 @@ _odict_keys_equal(PyODictObject *a, PyODictObject *b)
{
_ODictNode *node_a, *node_b;
// keep operands' state to detect undesired mutations
const size_t state_a = a->od_state;
const size_t state_b = b->od_state;
node_a = _odict_FIRST(a);
node_b = _odict_FIRST(b);
while (1) {
if (node_a == NULL && node_b == NULL)
if (node_a == NULL && node_b == NULL) {
/* success: hit the end of each at the same time */
return 1;
else if (node_a == NULL || node_b == NULL)
}
else if (node_a == NULL || node_b == NULL) {
/* unequal length */
return 0;
}
else {
int res = PyObject_RichCompareBool(
(PyObject *)_odictnode_KEY(node_a),
(PyObject *)_odictnode_KEY(node_b),
Py_EQ);
if (res < 0)
PyObject *key_a = Py_NewRef(_odictnode_KEY(node_a));
PyObject *key_b = Py_NewRef(_odictnode_KEY(node_b));
int res = PyObject_RichCompareBool(key_a, key_b, Py_EQ);
Py_DECREF(key_a);
Py_DECREF(key_b);
if (res < 0) {
return res;
else if (res == 0)
}
else if (a->od_state != state_a || b->od_state != state_b) {
PyErr_SetString(PyExc_RuntimeError,
"OrderedDict mutated during iteration");
return -1;
}
else if (res == 0) {
// This check comes after the check on the state
// in order for the exception to be set correctly.
return 0;
}
/* otherwise it must match, so move on to the next one */
node_a = _odictnode_NEXT(node_a);