[Python-checkins] cpython (merge 3.3 -> 3.4): merge 3.3 (#24407)

benjamin.peterson python-checkins at python.org
Sun Jul 5 05:54:13 CEST 2015


https://hg.python.org/cpython/rev/75da5acbfbe4
changeset:   96812:75da5acbfbe4
branch:      3.4
parent:      96769:34460219c0e0
parent:      96811:37fed8b02f00
user:        Benjamin Peterson <benjamin at python.org>
date:        Sat Jul 04 19:58:11 2015 -0500
summary:
  merge 3.3 (#24407)

files:
  Lib/test/test_dict.py |  14 ++++++++++++++
  Misc/NEWS             |   2 ++
  Objects/dictobject.c  |  26 +++++++++++++++++++-------
  3 files changed, 35 insertions(+), 7 deletions(-)


diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -937,6 +937,20 @@
                 d.popitem()
         self.check_reentrant_insertion(mutate)
 
+    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
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -32,6 +32,8 @@
 - Issue #23757:  PySequence_Tuple() incorrectly called the concrete list API
   when the data was a list subclass.
 
+- Issue #24407: Fix crash when dict is mutated while being updated.
+
 - Issue #24096: Make warnings.warn_explicit more robust against mutation of the
   warnings.filters list.
 
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1973,20 +1973,32 @@
             if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0)
                return -1;
         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];
+            key = entry->me_key;
+            hash = entry->me_hash;
             if (other->ma_values)
                 value = other->ma_values[i];
             else
                 value = entry->me_value;
 
-            if (value != NULL &&
-                (override ||
-                 PyDict_GetItem(a, entry->me_key) == NULL)) {
-                if (insertdict(mp, entry->me_key,
-                               entry->me_hash,
-                               value) != 0)
+            if (value != NULL) {
+                int err = 0;
+                Py_INCREF(key);
+                Py_INCREF(value);
+                if (override || PyDict_GetItem(a, key) == NULL)
+                    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;
+                }
             }
         }
     }

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list