mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
gh-119004: fix a crash in equality testing between OrderedDict (#121329)
This commit is contained in:
parent
e80dd3035f
commit
38a887dc3e
4 changed files with 145 additions and 11 deletions
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue