issue 2045: Infinite recursion when printing a subclass of defaultdict,

if default_factory is set to a bound method.

Backport of r60663.
This commit is contained in:
Amaury Forgeot d'Arc 2008-02-08 01:05:21 +00:00
parent ec4301e60f
commit 3e5f8a6975
3 changed files with 37 additions and 1 deletions

View File

@ -141,6 +141,29 @@ class TestDefaultDict(unittest.TestCase):
else: else:
self.fail("expected KeyError") 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(): def test_main():
test_support.run_unittest(TestDefaultDict) test_support.run_unittest(TestDefaultDict)

View File

@ -12,6 +12,9 @@ What's New in Python 2.5.2c1?
Core and builtins 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, - 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 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 the condition is false. Now the compiler correctly emits bytecode for the

View File

@ -1216,8 +1216,18 @@ defdict_repr(defdictobject *dd)
return NULL; return NULL;
if (dd->default_factory == NULL) if (dd->default_factory == NULL)
defrepr = PyString_FromString("None"); defrepr = PyString_FromString("None");
else
{
int status = Py_ReprEnter(dd->default_factory);
if (status != 0) {
if (status < 0)
return NULL;
defrepr = PyString_FromString("...");
}
else else
defrepr = PyObject_Repr(dd->default_factory); defrepr = PyObject_Repr(dd->default_factory);
Py_ReprLeave(dd->default_factory);
}
if (defrepr == NULL) { if (defrepr == NULL) {
Py_DECREF(baserepr); Py_DECREF(baserepr);
return NULL; return NULL;