Skip to content

Commit cef423c

Browse files
miss-islingtonKowalskiThomasmvanhorn
authored
[3.13] gh-145492: Fix defaultdict __repr__ infinite recursion (GH-145659) (GH-145746)
(cherry picked from commit 2d35f9b) Includes test fix-up from GH-145788 (cherry picked from commit aa4240e) Co-authored-by: Thomas Kowalski <thom.kowa@gmail.com> Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com>
1 parent 881cc06 commit cef423c

File tree

3 files changed

+21
-2
lines changed

3 files changed

+21
-2
lines changed

Lib/test/test_defaultdict.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,5 +204,20 @@ def default_factory():
204204
self.assertEqual(test_dict[key], 2)
205205
self.assertEqual(count, 2)
206206

207+
def test_repr_recursive_factory(self):
208+
# gh-145492: defaultdict.__repr__ should not cause infinite recursion
209+
# when the factory's __repr__ calls repr() on the defaultdict.
210+
class ProblematicFactory:
211+
def __call__(self):
212+
return {}
213+
def __repr__(self):
214+
repr(dd)
215+
return f"ProblematicFactory for {dd}"
216+
217+
dd = defaultdict(ProblematicFactory())
218+
# Should not raise RecursionError
219+
r = repr(dd)
220+
self.assertIn("ProblematicFactory for", r)
221+
207222
if __name__ == "__main__":
208223
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix infinite recursion in :class:`collections.defaultdict` ``__repr__``
2+
when a ``defaultdict`` contains itself. Based on analysis by KowalskiThomas
3+
in :gh:`145492`.

Modules/_collectionsmodule.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,9 +2337,10 @@ defdict_repr(defdictobject *dd)
23372337
}
23382338
defrepr = PyUnicode_FromString("...");
23392339
}
2340-
else
2340+
else {
23412341
defrepr = PyObject_Repr(dd->default_factory);
2342-
Py_ReprLeave(dd->default_factory);
2342+
Py_ReprLeave(dd->default_factory);
2343+
}
23432344
}
23442345
if (defrepr == NULL) {
23452346
Py_DECREF(baserepr);

0 commit comments

Comments
 (0)