summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmaury Forgeot d'Arc <amauryfa@gmail.com>2008-02-08 01:05:21 (GMT)
committerAmaury Forgeot d'Arc <amauryfa@gmail.com>2008-02-08 01:05:21 (GMT)
commit3e5f8a6975cb7f7c3dc9f84686f27c49bc4aa75a (patch)
treeea8428d58e9dc2798ad2374042caea5ee9bee6d4
parentec4301e60f8380d696115b598fea88cea239947c (diff)
downloadcpython-3e5f8a6975cb7f7c3dc9f84686f27c49bc4aa75a.zip
cpython-3e5f8a6975cb7f7c3dc9f84686f27c49bc4aa75a.tar.gz
cpython-3e5f8a6975cb7f7c3dc9f84686f27c49bc4aa75a.tar.bz2
issue 2045: Infinite recursion when printing a subclass of defaultdict,
if default_factory is set to a bound method. Backport of r60663.
-rw-r--r--Lib/test/test_defaultdict.py23
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/collectionsmodule.c12
3 files changed, 37 insertions, 1 deletions
diff --git a/Lib/test/test_defaultdict.py b/Lib/test/test_defaultdict.py
index 08be005..5724fd0 100644
--- a/Lib/test/test_defaultdict.py
+++ b/Lib/test/test_defaultdict.py
@@ -141,6 +141,29 @@ class TestDefaultDict(unittest.TestCase):
else:
self.fail("expected KeyError")
+ def test_recursive_repr(self):
+ # Issue2045: stack overflow when default_factory is a bound method
+ class sub(defaultdict):
+ def __init__(self):
+ self.default_factory = self._factory
+ def _factory(self):
+ return []
+ d = sub()
+ self.assert_(repr(d).startswith(
+ "defaultdict(<bound method sub._factory of defaultdict(..."))
+
+ # NOTE: printing a subclass of a builtin type does not call its
+ # tp_print slot. So this part is essentially the same test as above.
+ tfn = tempfile.mktemp()
+ try:
+ f = open(tfn, "w+")
+ try:
+ print >>f, d
+ finally:
+ f.close()
+ finally:
+ os.remove(tfn)
+
def test_main():
test_support.run_unittest(TestDefaultDict)
diff --git a/Misc/NEWS b/Misc/NEWS
index e3a4ace..cf73bca 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.5.2c1?
Core and builtins
-----------------
+- Issue #2045: Fix an infinite recursion triggered when printing a subclass of
+ collections.defaultdict, if its default_factory is set to a bound method.
+
- Issue #1920: "while 0" statements were completely removed by the compiler,
even in the presence of an "else" clause, which is supposed to be run when
the condition is false. Now the compiler correctly emits bytecode for the
diff --git a/Modules/collectionsmodule.c b/Modules/collectionsmodule.c
index 9d128fc..dd3c0b7 100644
--- a/Modules/collectionsmodule.c
+++ b/Modules/collectionsmodule.c
@@ -1217,7 +1217,17 @@ defdict_repr(defdictobject *dd)
if (dd->default_factory == NULL)
defrepr = PyString_FromString("None");
else
- defrepr = PyObject_Repr(dd->default_factory);
+ {
+ int status = Py_ReprEnter(dd->default_factory);
+ if (status != 0) {
+ if (status < 0)
+ return NULL;
+ defrepr = PyString_FromString("...");
+ }
+ else
+ defrepr = PyObject_Repr(dd->default_factory);
+ Py_ReprLeave(dd->default_factory);
+ }
if (defrepr == NULL) {
Py_DECREF(baserepr);
return NULL;