From d1f2cb37a2d1cc7b098abf6bc403fb5d43128051 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Wed, 31 Oct 2012 14:05:55 -0400 Subject: only fast-path fromkeys() when the constructor returns a empty dict (closes #16345) --- Lib/test/test_dict.py | 8 ++++++ Misc/NEWS | 3 +++ Objects/dictobject.c | 67 ++++++++++++++++++++++++++------------------------- 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index d2740a3..9666f9a 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -254,6 +254,14 @@ class DictTest(unittest.TestCase): d = dict(zip(range(6), range(6))) self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) + class baddict3(dict): + def __new__(cls): + return d + d = {i : i for i in range(10)} + res = d.copy() + res.update(a=None, b=None, c=None) + self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res) + def test_copy(self): d = {1:1, 2:2, 3:3} self.assertEqual(d.copy(), {1:1, 2:2, 3:3}) diff --git a/Misc/NEWS b/Misc/NEWS index 434f221..bd6cd80 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.2.4 Core and Builtins ----------------- +- Issue #16345: Fix an infinite loop when ``fromkeys`` on a dict subclass + recieved a nonempty dict from the constructor. + - Issue #16197: Update winreg docstrings and documentation to match code. Patch by Zachary Ware. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 27de10d..d3c5eac 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1335,49 +1335,50 @@ dict_fromkeys(PyObject *cls, PyObject *args) if (d == NULL) return NULL; - if (PyDict_CheckExact(d) && PyDict_CheckExact(seq)) { - PyDictObject *mp = (PyDictObject *)d; - PyObject *oldvalue; - Py_ssize_t pos = 0; - PyObject *key; - Py_hash_t hash; - - if (dictresize(mp, Py_SIZE(seq))) { - Py_DECREF(d); - return NULL; - } - - while (_PyDict_Next(seq, &pos, &key, &oldvalue, &hash)) { - Py_INCREF(key); - Py_INCREF(value); - if (insertdict(mp, key, hash, value)) { + if (PyDict_CheckExact(d) && PyDict_Size(d) == 0) { + if (PyDict_CheckExact(seq)) { + PyDictObject *mp = (PyDictObject *)d; + PyObject *oldvalue; + Py_ssize_t pos = 0; + PyObject *key; + Py_hash_t hash; + + if (dictresize(mp, Py_SIZE(seq))) { Py_DECREF(d); return NULL; } - } - return d; - } - if (PyDict_CheckExact(d) && PyAnySet_CheckExact(seq)) { - PyDictObject *mp = (PyDictObject *)d; - Py_ssize_t pos = 0; - PyObject *key; - Py_hash_t hash; - - if (dictresize(mp, PySet_GET_SIZE(seq))) { - Py_DECREF(d); - return NULL; + while (_PyDict_Next(seq, &pos, &key, &oldvalue, &hash)) { + Py_INCREF(key); + Py_INCREF(value); + if (insertdict(mp, key, hash, value)) { + Py_DECREF(d); + return NULL; + } + } + return d; } + if (PyAnySet_CheckExact(seq)) { + PyDictObject *mp = (PyDictObject *)d; + Py_ssize_t pos = 0; + PyObject *key; + Py_hash_t hash; - while (_PySet_NextEntry(seq, &pos, &key, &hash)) { - Py_INCREF(key); - Py_INCREF(value); - if (insertdict(mp, key, hash, value)) { + if (dictresize(mp, PySet_GET_SIZE(seq))) { Py_DECREF(d); return NULL; } + + while (_PySet_NextEntry(seq, &pos, &key, &hash)) { + Py_INCREF(key); + Py_INCREF(value); + if (insertdict(mp, key, hash, value)) { + Py_DECREF(d); + return NULL; + } + } + return d; } - return d; } it = PyObject_GetIter(seq); -- cgit v0.12