Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1a99750

Browse files
committed
Fix SF bug #667147, Segmentation fault printing str subclass
Fix infinite recursion which occurred when printing an object whose __str__() returned self. Will backport
1 parent a974b39 commit 1a99750

3 files changed

Lines changed: 43 additions & 4 deletions

File tree

Lib/test/test_descr.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Test enhancements related to descriptors and new-style classes
22

3-
from test.test_support import verify, vereq, verbose, TestFailed, TESTFN
3+
from test.test_support import verify, vereq, verbose, TestFailed, TESTFN, get_original_stdout
44
from copy import deepcopy
55
import warnings
66

@@ -1821,6 +1821,29 @@ def unsafecmp(a, b):
18211821
unsafecmp(1, 1L)
18221822
unsafecmp(1L, 1)
18231823

1824+
class Letter(str):
1825+
def __new__(cls, letter):
1826+
if letter == 'EPS':
1827+
return str.__new__(cls)
1828+
return str.__new__(cls, letter)
1829+
def __str__(self):
1830+
if not self:
1831+
return 'EPS'
1832+
return self
1833+
1834+
# sys.stdout needs to be the original to trigger the recursion bug
1835+
import sys
1836+
test_stdout = sys.stdout
1837+
sys.stdout = get_original_stdout()
1838+
try:
1839+
# nothing should actually be printed, this should raise an exception
1840+
print Letter('w')
1841+
except RuntimeError:
1842+
pass
1843+
else:
1844+
raise TestFailed, "expected a RuntimeError for print recursion"
1845+
sys.stdout = test_stdout
1846+
18241847
def weakrefs():
18251848
if verbose: print "Testing weak references..."
18261849
import weakref

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Core and builtins
1818
Passing None is semantically identical to calling sort() with no
1919
arguments.
2020

21+
- Fixed crash when printing a subclass of str and __str__ returned self.
22+
See SF bug #667147.
23+
2124
Extension modules
2225
-----------------
2326

Objects/object.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,15 @@ _PyObject_Del(PyObject *op)
158158
PyObject_FREE(op);
159159
}
160160

161-
int
162-
PyObject_Print(PyObject *op, FILE *fp, int flags)
161+
/* Implementation of PyObject_Print with recursion checking */
162+
static int
163+
internal_print(PyObject *op, FILE *fp, int flags, int nesting)
163164
{
164165
int ret = 0;
166+
if (nesting > 10) {
167+
PyErr_SetString(PyExc_RuntimeError, "print recursion");
168+
return -1;
169+
}
165170
if (PyErr_CheckSignals())
166171
return -1;
167172
#ifdef USE_STACKCHECK
@@ -187,7 +192,8 @@ PyObject_Print(PyObject *op, FILE *fp, int flags)
187192
if (s == NULL)
188193
ret = -1;
189194
else {
190-
ret = PyObject_Print(s, fp, Py_PRINT_RAW);
195+
ret = internal_print(s, fp, Py_PRINT_RAW,
196+
nesting+1);
191197
}
192198
Py_XDECREF(s);
193199
}
@@ -204,6 +210,13 @@ PyObject_Print(PyObject *op, FILE *fp, int flags)
204210
return ret;
205211
}
206212

213+
int
214+
PyObject_Print(PyObject *op, FILE *fp, int flags)
215+
{
216+
return internal_print(op, fp, flags, 0);
217+
}
218+
219+
207220
/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */
208221
void _PyObject_Dump(PyObject* op)
209222
{

0 commit comments

Comments
 (0)