bpo-25455: Fixed crashes in repr of recursive buffered file-like objects. (#514)
This commit is contained in:
parent
77ed11552d
commit
a5af6e1af7
@ -10,7 +10,7 @@ from weakref import proxy
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from test.support import (TESTFN, TESTFN_UNICODE, check_warnings, run_unittest,
|
from test.support import (TESTFN, TESTFN_UNICODE, check_warnings, run_unittest,
|
||||||
make_bad_fd, cpython_only)
|
make_bad_fd, cpython_only, swap_attr)
|
||||||
from collections import UserList
|
from collections import UserList
|
||||||
|
|
||||||
import _io # C implementation of io
|
import _io # C implementation of io
|
||||||
@ -176,6 +176,12 @@ class AutoFileTests:
|
|||||||
finally:
|
finally:
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
|
|
||||||
|
def testRecursiveRepr(self):
|
||||||
|
# Issue #25455
|
||||||
|
with swap_attr(self.f, 'name', self.f):
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
repr(self.f) # Should not crash
|
||||||
|
|
||||||
def testErrors(self):
|
def testErrors(self):
|
||||||
f = self.f
|
f = self.f
|
||||||
self.assertFalse(f.isatty())
|
self.assertFalse(f.isatty())
|
||||||
|
@ -1014,6 +1014,16 @@ class CommonBufferedTests:
|
|||||||
raw.name = b"dummy"
|
raw.name = b"dummy"
|
||||||
self.assertEqual(repr(b), "<%s name=b'dummy'>" % clsname)
|
self.assertEqual(repr(b), "<%s name=b'dummy'>" % clsname)
|
||||||
|
|
||||||
|
def test_recursive_repr(self):
|
||||||
|
# Issue #25455
|
||||||
|
raw = self.MockRawIO()
|
||||||
|
b = self.tp(raw)
|
||||||
|
with support.swap_attr(raw, 'name', b):
|
||||||
|
try:
|
||||||
|
repr(b) # Should not crash
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
|
||||||
def test_flush_error_on_close(self):
|
def test_flush_error_on_close(self):
|
||||||
# Test that buffered file is closed despite failed flush
|
# Test that buffered file is closed despite failed flush
|
||||||
# and that flush() is called before file closed.
|
# and that flush() is called before file closed.
|
||||||
@ -2435,6 +2445,16 @@ class TextIOWrapperTest(unittest.TestCase):
|
|||||||
t.buffer.detach()
|
t.buffer.detach()
|
||||||
repr(t) # Should not raise an exception
|
repr(t) # Should not raise an exception
|
||||||
|
|
||||||
|
def test_recursive_repr(self):
|
||||||
|
# Issue #25455
|
||||||
|
raw = self.BytesIO()
|
||||||
|
t = self.TextIOWrapper(raw)
|
||||||
|
with support.swap_attr(raw, 'name', t):
|
||||||
|
try:
|
||||||
|
repr(t) # Should not crash
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
|
||||||
def test_line_buffering(self):
|
def test_line_buffering(self):
|
||||||
r = self.BytesIO()
|
r = self.BytesIO()
|
||||||
b = self.BufferedWriter(r, 1000)
|
b = self.BufferedWriter(r, 1000)
|
||||||
|
@ -281,6 +281,8 @@ Extension Modules
|
|||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- bpo-25455: Fixed crashes in repr of recursive buffered file-like objects.
|
||||||
|
|
||||||
- bpo-29800: Fix crashes in partial.__repr__ if the keys of partial.keywords
|
- bpo-29800: Fix crashes in partial.__repr__ if the keys of partial.keywords
|
||||||
are not strings. Patch by Michael Seifert.
|
are not strings. Patch by Michael Seifert.
|
||||||
|
|
||||||
|
@ -1415,8 +1415,18 @@ buffered_repr(buffered *self)
|
|||||||
res = PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
|
res = PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res = PyUnicode_FromFormat("<%s name=%R>",
|
int status = Py_ReprEnter((PyObject *)self);
|
||||||
Py_TYPE(self)->tp_name, nameobj);
|
res = NULL;
|
||||||
|
if (status == 0) {
|
||||||
|
res = PyUnicode_FromFormat("<%s name=%R>",
|
||||||
|
Py_TYPE(self)->tp_name, nameobj);
|
||||||
|
Py_ReprLeave((PyObject *)self);
|
||||||
|
}
|
||||||
|
else if (status > 0) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
|
"reentrant call inside %s.__repr__",
|
||||||
|
Py_TYPE(self)->tp_name);
|
||||||
|
}
|
||||||
Py_DECREF(nameobj);
|
Py_DECREF(nameobj);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -1082,9 +1082,19 @@ fileio_repr(fileio *self)
|
|||||||
self->fd, mode_string(self), self->closefd ? "True" : "False");
|
self->fd, mode_string(self), self->closefd ? "True" : "False");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res = PyUnicode_FromFormat(
|
int status = Py_ReprEnter((PyObject *)self);
|
||||||
"<_io.FileIO name=%R mode='%s' closefd=%s>",
|
res = NULL;
|
||||||
nameobj, mode_string(self), self->closefd ? "True" : "False");
|
if (status == 0) {
|
||||||
|
res = PyUnicode_FromFormat(
|
||||||
|
"<_io.FileIO name=%R mode='%s' closefd=%s>",
|
||||||
|
nameobj, mode_string(self), self->closefd ? "True" : "False");
|
||||||
|
Py_ReprLeave((PyObject *)self);
|
||||||
|
}
|
||||||
|
else if (status > 0) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
|
"reentrant call inside %s.__repr__",
|
||||||
|
Py_TYPE(self)->tp_name);
|
||||||
|
}
|
||||||
Py_DECREF(nameobj);
|
Py_DECREF(nameobj);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -2483,6 +2483,7 @@ static PyObject *
|
|||||||
textiowrapper_repr(textio *self)
|
textiowrapper_repr(textio *self)
|
||||||
{
|
{
|
||||||
PyObject *nameobj, *modeobj, *res, *s;
|
PyObject *nameobj, *modeobj, *res, *s;
|
||||||
|
int status;
|
||||||
|
|
||||||
CHECK_INITIALIZED(self);
|
CHECK_INITIALIZED(self);
|
||||||
|
|
||||||
@ -2490,6 +2491,15 @@ textiowrapper_repr(textio *self)
|
|||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
status = Py_ReprEnter((PyObject *)self);
|
||||||
|
if (status != 0) {
|
||||||
|
if (status > 0) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
|
"reentrant call inside %s.__repr__",
|
||||||
|
Py_TYPE(self)->tp_name);
|
||||||
|
}
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
|
nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
|
||||||
if (nameobj == NULL) {
|
if (nameobj == NULL) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_Exception))
|
if (PyErr_ExceptionMatches(PyExc_Exception))
|
||||||
@ -2504,7 +2514,7 @@ textiowrapper_repr(textio *self)
|
|||||||
goto error;
|
goto error;
|
||||||
PyUnicode_AppendAndDel(&res, s);
|
PyUnicode_AppendAndDel(&res, s);
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
modeobj = _PyObject_GetAttrId((PyObject *) self, &PyId_mode);
|
modeobj = _PyObject_GetAttrId((PyObject *) self, &PyId_mode);
|
||||||
if (modeobj == NULL) {
|
if (modeobj == NULL) {
|
||||||
@ -2520,14 +2530,21 @@ textiowrapper_repr(textio *self)
|
|||||||
goto error;
|
goto error;
|
||||||
PyUnicode_AppendAndDel(&res, s);
|
PyUnicode_AppendAndDel(&res, s);
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
s = PyUnicode_FromFormat("%U encoding=%R>",
|
s = PyUnicode_FromFormat("%U encoding=%R>",
|
||||||
res, self->encoding);
|
res, self->encoding);
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
|
if (status == 0) {
|
||||||
|
Py_ReprLeave((PyObject *)self);
|
||||||
|
}
|
||||||
return s;
|
return s;
|
||||||
error:
|
|
||||||
|
error:
|
||||||
Py_XDECREF(res);
|
Py_XDECREF(res);
|
||||||
|
if (status == 0) {
|
||||||
|
Py_ReprLeave((PyObject *)self);
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user