Kaydet (Commit) a82f77fb authored tarafından Benjamin Peterson's avatar Benjamin Peterson

protect against mutation of the dict during insertion (closes #24407)

üst dac3ab84
...@@ -906,6 +906,21 @@ class DictTest(unittest.TestCase): ...@@ -906,6 +906,21 @@ class DictTest(unittest.TestCase):
f.a = 'a' f.a = 'a'
self.assertEqual(f.__dict__, {1:1, 'a':'a'}) self.assertEqual(f.__dict__, {1:1, 'a':'a'})
def test_merge_and_mutate(self):
class X:
def __hash__(self):
return 0
def __eq__(self, o):
other.clear()
return False
l = [(i,0) for i in range(1, 1337)]
other = dict(l)
other[X()] = 0
d = {X(): 0, 1: 1}
self.assertRaises(RuntimeError, d.update, other)
from test import mapping_tests from test import mapping_tests
class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
......
...@@ -10,6 +10,8 @@ What's New in Python 3.3.7? ...@@ -10,6 +10,8 @@ What's New in Python 3.3.7?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #24407: Fix crash when dict is mutated while being updated.
- Issue #24096: Make warnings.warn_explicit more robust against mutation of the - Issue #24096: Make warnings.warn_explicit more robust against mutation of the
warnings.filters list. warnings.filters list.
......
...@@ -1941,20 +1941,32 @@ PyDict_Merge(PyObject *a, PyObject *b, int override) ...@@ -1941,20 +1941,32 @@ PyDict_Merge(PyObject *a, PyObject *b, int override)
if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0)
return -1; return -1;
for (i = 0, n = DK_SIZE(other->ma_keys); i < n; i++) { for (i = 0, n = DK_SIZE(other->ma_keys); i < n; i++) {
PyObject *value; PyObject *key, *value;
Py_hash_t hash;
entry = &other->ma_keys->dk_entries[i]; entry = &other->ma_keys->dk_entries[i];
key = entry->me_key;
hash = entry->me_hash;
if (other->ma_values) if (other->ma_values)
value = other->ma_values[i]; value = other->ma_values[i];
else else
value = entry->me_value; value = entry->me_value;
if (value != NULL && if (value != NULL) {
(override || int err = 0;
PyDict_GetItem(a, entry->me_key) == NULL)) { Py_INCREF(key);
if (insertdict(mp, entry->me_key, Py_INCREF(value);
entry->me_hash, if (override || PyDict_GetItem(a, key) == NULL)
value) != 0) err = insertdict(mp, key, hash, value);
Py_DECREF(value);
Py_DECREF(key);
if (err != 0)
return -1;
if (n != DK_SIZE(other->ma_keys)) {
PyErr_SetString(PyExc_RuntimeError,
"dict mutated during update");
return -1; return -1;
}
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment