From 9bcbc6cba385a83cac8f1ff430cad7617184d2bc Mon Sep 17 00:00:00 2001 From: Oren Milman Date: Sat, 26 Aug 2017 20:29:40 +0300 Subject: [PATCH] [3.6] bpo-31271: Fix an assertion failure in io.TextIOWrapper.write. (GH-3201) (#3209) (cherry picked from commit a5b4ea15b61e3f3985f4f0748a18f8b888a63532) --- Lib/test/test_io.py | 8 ++++++++ .../2017-08-25-20-43-22.bpo-31271.YMduKF.rst | 2 ++ Modules/_io/textio.c | 7 +++++++ 3 files changed, 17 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2017-08-25-20-43-22.bpo-31271.YMduKF.rst diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 6a2c7a9fca4..7057c927c3f 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -3163,6 +3163,14 @@ class TextIOWrapperTest(unittest.TestCase): t = self.TextIOWrapper(self.StringIO('a')) self.assertRaises(TypeError, t.read) + def test_illegal_encoder(self): + # Issue 31271: Calling write() while the return value of encoder's + # encode() is invalid shouldn't cause an assertion failure. + rot13 = codecs.lookup("rot13") + with support.swap_attr(rot13, '_is_text_encoding', True): + t = io.TextIOWrapper(io.BytesIO(b'foo'), encoding="rot13") + self.assertRaises(TypeError, t.write, 'bar') + def test_illegal_decoder(self): # Issue #17106 # Bypass the early encoding check added in issue 20404 diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-08-25-20-43-22.bpo-31271.YMduKF.rst b/Misc/NEWS.d/next/Core and Builtins/2017-08-25-20-43-22.bpo-31271.YMduKF.rst new file mode 100644 index 00000000000..7bb78801057 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-08-25-20-43-22.bpo-31271.YMduKF.rst @@ -0,0 +1,2 @@ +Fix an assertion failure in the write() method of `io.TextIOWrapper`, when +the encoder doesn't return a bytes object. Patch by Oren Milman. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 61adcf60508..801bb1745bb 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1331,6 +1331,13 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) Py_DECREF(text); if (b == NULL) return NULL; + if (!PyBytes_Check(b)) { + PyErr_Format(PyExc_TypeError, + "encoder should return a bytes object, not '%.200s'", + Py_TYPE(b)->tp_name); + Py_DECREF(b); + return NULL; + } if (self->pending_bytes == NULL) { self->pending_bytes = PyList_New(0);