Index: Objects/object.c =================================================================== --- Objects/object.c (revision 58125) +++ Objects/object.c (working copy) @@ -404,7 +404,12 @@ if (Py_Type(v)->tp_str == NULL) return PyObject_Repr(v); + /* It is possible for a type to have a tp_str representation that loops + infinitely. */ + if (Py_EnterRecursiveCall(" while getting the str of an object")) + return NULL; res = (*Py_Type(v)->tp_str)(v); + Py_LeaveRecursiveCall(); if (res == NULL) return NULL; type_ok = PyString_Check(res); Index: Objects/tupleobject.c =================================================================== --- Objects/tupleobject.c (revision 58125) +++ Objects/tupleobject.c (working copy) @@ -208,6 +208,15 @@ PyObject *s, *temp; PyObject *pieces, *result = NULL; + /* While not mutable, it is still possible to end up with a cycle in a + tuple through an object that stores itself within a tuple (and thus + infinitely asks for the repr of itself). This should only be + possible within a type. */ + i = Py_ReprEnter((PyObject *)v); + if (i != 0) { + return i > 0 ? PyString_FromString("(...)") : NULL; + } + n = Py_Size(v); if (n == 0) return PyString_FromString("()"); @@ -218,7 +227,10 @@ /* Do repr() on each element. */ for (i = 0; i < n; ++i) { + if (Py_EnterRecursiveCall(" while getting the repr of a tuple")) + goto Done; s = PyObject_Repr(v->ob_item[i]); + Py_LeaveRecursiveCall(); if (s == NULL) goto Done; PyTuple_SET_ITEM(pieces, i, s); @@ -253,6 +265,7 @@ Done: Py_DECREF(pieces); + Py_ReprLeave((PyObject *)v); return result; }