From 1a9975014f7ddc583a2428fe47d0e17261f98b46 Mon Sep 17 00:00:00 2001 From: Neal Norwitz Date: Mon, 13 Jan 2003 20:13:12 +0000 Subject: Fix SF bug #667147, Segmentation fault printing str subclass Fix infinite recursion which occurred when printing an object whose __str__() returned self. Will backport --- Lib/test/test_descr.py | 25 ++++++++++++++++++++++++- Misc/NEWS | 3 +++ Objects/object.c | 19 ++++++++++++++++--- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 023fcc8..da4bd03 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1,6 +1,6 @@ # Test enhancements related to descriptors and new-style classes -from test.test_support import verify, vereq, verbose, TestFailed, TESTFN +from test.test_support import verify, vereq, verbose, TestFailed, TESTFN, get_original_stdout from copy import deepcopy import warnings @@ -1821,6 +1821,29 @@ def specials(): unsafecmp(1, 1L) unsafecmp(1L, 1) + class Letter(str): + def __new__(cls, letter): + if letter == 'EPS': + return str.__new__(cls) + return str.__new__(cls, letter) + def __str__(self): + if not self: + return 'EPS' + return self + + # sys.stdout needs to be the original to trigger the recursion bug + import sys + test_stdout = sys.stdout + sys.stdout = get_original_stdout() + try: + # nothing should actually be printed, this should raise an exception + print Letter('w') + except RuntimeError: + pass + else: + raise TestFailed, "expected a RuntimeError for print recursion" + sys.stdout = test_stdout + def weakrefs(): if verbose: print "Testing weak references..." import weakref diff --git a/Misc/NEWS b/Misc/NEWS index 1fa1c8c..5f415d4 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Core and builtins Passing None is semantically identical to calling sort() with no arguments. +- Fixed crash when printing a subclass of str and __str__ returned self. + See SF bug #667147. + Extension modules ----------------- diff --git a/Objects/object.c b/Objects/object.c index 3328643..e3234de 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -158,10 +158,15 @@ _PyObject_Del(PyObject *op) PyObject_FREE(op); } -int -PyObject_Print(PyObject *op, FILE *fp, int flags) +/* Implementation of PyObject_Print with recursion checking */ +static int +internal_print(PyObject *op, FILE *fp, int flags, int nesting) { int ret = 0; + if (nesting > 10) { + PyErr_SetString(PyExc_RuntimeError, "print recursion"); + return -1; + } if (PyErr_CheckSignals()) return -1; #ifdef USE_STACKCHECK @@ -187,7 +192,8 @@ PyObject_Print(PyObject *op, FILE *fp, int flags) if (s == NULL) ret = -1; else { - ret = PyObject_Print(s, fp, Py_PRINT_RAW); + ret = internal_print(s, fp, Py_PRINT_RAW, + nesting+1); } Py_XDECREF(s); } @@ -204,6 +210,13 @@ PyObject_Print(PyObject *op, FILE *fp, int flags) return ret; } +int +PyObject_Print(PyObject *op, FILE *fp, int flags) +{ + return internal_print(op, fp, flags, 0); +} + + /* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */ void _PyObject_Dump(PyObject* op) { -- cgit v0.12