diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index caca0333e0d82f..3dc6e9ffcac157 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2702,6 +2702,26 @@ def _make_illegal_wrapper(): #t = _make_illegal_wrapper() #self.assertRaises(TypeError, t.read) + # Issue 31243: calling read() while the return value of decoder's + # getstate() is invalid should neither crash the interpreter nor + # raise a SystemError. + def _make_very_illegal_wrapper(getstate_ret_val): + class BadDecoder: + def getstate(self): + return getstate_ret_val + def _get_bad_decoder(dummy): + return BadDecoder() + quopri = codecs.lookup("quopri_codec") + with support.swap_attr(quopri, 'incrementaldecoder', + _get_bad_decoder): + return _make_illegal_wrapper() + t = _make_very_illegal_wrapper(42) + with self.maybeRaises(TypeError): + t.read(42) + t = _make_very_illegal_wrapper(()) + with self.maybeRaises(TypeError): + t.read(42) + class CTextIOWrapperTest(TextIOWrapperTest): diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-08-29-14-24-34.bpo-31243.tr0E4V.rst b/Misc/NEWS.d/next/Core and Builtins/2017-08-29-14-24-34.bpo-31243.tr0E4V.rst new file mode 100644 index 00000000000000..166458f2b785ab --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-08-29-14-24-34.bpo-31243.tr0E4V.rst @@ -0,0 +1,2 @@ +Fix a crash in some methods of `io.TextIOWrapper`, when the decoder's state +is invalid. Patch by Oren Milman. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index f13dcb4366e06f..d9e036db386d3b 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1416,7 +1416,7 @@ textiowrapper_read_chunk(textio *self) /* Given this, we know there was a valid snapshot point * len(dec_buffer) bytes ago with decoder state (b'', dec_flags). */ - if (PyArg_Parse(state, "(OO)", &dec_buffer, &dec_flags) < 0) { + if (!PyArg_Parse(state, "(OO)", &dec_buffer, &dec_flags)) { Py_DECREF(state); return -1; } diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index a5e3f07667d07a..ecc473cf4c1521 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -911,8 +911,9 @@ test_L_code(PyObject *self) PyTuple_SET_ITEM(tuple, 0, num); value = -1; - if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0) + if (!PyArg_ParseTuple(tuple, "L:test_L_code", &value)) { return NULL; + } if (value != 42) return raiseTestError("test_L_code", "L code returned wrong value for long 42"); @@ -925,8 +926,9 @@ test_L_code(PyObject *self) PyTuple_SET_ITEM(tuple, 0, num); value = -1; - if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0) + if (!PyArg_ParseTuple(tuple, "L:test_L_code", &value)) { return NULL; + } if (value != 42) return raiseTestError("test_L_code", "L code returned wrong value for int 42"); @@ -1207,8 +1209,9 @@ test_k_code(PyObject *self) PyTuple_SET_ITEM(tuple, 0, num); value = 0; - if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0) + if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) { return NULL; + } if (value != ULONG_MAX) return raiseTestError("test_k_code", "k code returned wrong value for long 0xFFF...FFF"); @@ -1226,8 +1229,9 @@ test_k_code(PyObject *self) PyTuple_SET_ITEM(tuple, 0, num); value = 0; - if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0) + if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) { return NULL; + } if (value != (unsigned long)-0x42) return raiseTestError("test_k_code", "k code returned wrong value for long -0xFFF..000042"); @@ -1587,14 +1591,16 @@ test_u_code(PyObject *self) PyTuple_SET_ITEM(tuple, 0, obj); value = 0; - if (PyArg_ParseTuple(tuple, "u:test_u_code", &value) < 0) + if (!PyArg_ParseTuple(tuple, "u:test_u_code", &value)) { return NULL; + } if (value != PyUnicode_AS_UNICODE(obj)) return raiseTestError("test_u_code", "u code returned wrong value for u'test'"); value = 0; - if (PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len) < 0) + if (!PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len)) { return NULL; + } if (value != PyUnicode_AS_UNICODE(obj) || len != PyUnicode_GET_SIZE(obj)) return raiseTestError("test_u_code", @@ -1692,8 +1698,9 @@ test_empty_argparse(PyObject *self) tuple = PyTuple_New(0); if (!tuple) return NULL; - if ((result = PyArg_ParseTuple(tuple, "|:test_empty_argparse")) < 0) + if (!(result = PyArg_ParseTuple(tuple, "|:test_empty_argparse"))) { goto done; + } dict = PyDict_New(); if (!dict) goto done; @@ -1701,8 +1708,9 @@ test_empty_argparse(PyObject *self) done: Py_DECREF(tuple); Py_XDECREF(dict); - if (result < 0) + if (!result) { return NULL; + } else { Py_RETURN_NONE; } @@ -2494,8 +2502,9 @@ test_raise_signal(PyObject* self, PyObject *args) { int signum, err; - if (PyArg_ParseTuple(args, "i:raise_signal", &signum) < 0) + if (!PyArg_ParseTuple(args, "i:raise_signal", &signum)) { return NULL; + } err = raise(signum); if (err)