summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_dict.py14
-rw-r--r--Lib/test/test_unpack_ex.py3
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/dictobject.c26
-rw-r--r--Python/ceval.c15
-rw-r--r--Tools/msi/msi.targets2
6 files changed, 50 insertions, 14 deletions
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 9553c66d14..2488b63474 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -937,6 +937,20 @@ class DictTest(unittest.TestCase):
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/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py
index 01f57b95e7..d27eef0397 100644
--- a/Lib/test/test_unpack_ex.py
+++ b/Lib/test/test_unpack_ex.py
@@ -128,6 +128,9 @@ Dict display element unpacking
... for i in range(1000)) + "}"))
1000
+ >>> {0:1, **{0:2}, 0:3, 0:4}
+ {0: 4}
+
List comprehension element unpacking
>>> a, b, c = [0, 1, 2], 3, 4
diff --git a/Misc/NEWS b/Misc/NEWS
index 7bbc037486..2bd6bcb84e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@ Release date: 2015-07-26
Core and Builtins
-----------------
+- Issue #24569: Make PEP 448 dictionary evaluation more consistent.
+
+- Issue #24407: Fix crash when dict is mutated while being updated.
+
Library
-------
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 3791d5b398..5a7de9e539 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2039,20 +2039,32 @@ PyDict_Merge(PyObject *a, PyObject *b, int override)
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;
+ }
}
}
}
diff --git a/Python/ceval.c b/Python/ceval.c
index e68ae33bfd..ac52ad91e2 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2561,22 +2561,25 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
TARGET(BUILD_MAP) {
+ int i;
PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg);
if (map == NULL)
goto error;
- while (--oparg >= 0) {
+ for (i = oparg; i > 0; i--) {
int err;
- PyObject *value = TOP();
- PyObject *key = SECOND();
- STACKADJ(-2);
+ PyObject *key = PEEK(2*i);
+ PyObject *value = PEEK(2*i - 1);
err = PyDict_SetItem(map, key, value);
- Py_DECREF(value);
- Py_DECREF(key);
if (err != 0) {
Py_DECREF(map);
goto error;
}
}
+
+ while (oparg--) {
+ Py_DECREF(POP());
+ Py_DECREF(POP());
+ }
PUSH(map);
DISPATCH();
}
diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets
index 34b8747fff..2431dc2f2f 100644
--- a/Tools/msi/msi.targets
+++ b/Tools/msi/msi.targets
@@ -24,7 +24,7 @@
</ItemGroup>
</Target>
- <Target Name="_TransformWxlTemplates" AfterTargets="PrepareForBuild">
+ <Target Name="_TransformWxlTemplates" AfterTargets="PrepareForBuild" Inputs="@(WxlTemplate);$(PySourcePath)include\patchlevel.h" Outputs="$(IntermediateOutputPath)%(Filename).wxl">
<PropertyGroup>
<_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`))</_Content>
<_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl))</_ExistingContent>