diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2013-02-03 15:07:32 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2013-02-03 15:07:32 (GMT) |
commit | d03ce4ae3d71ba84e1e30cf0cf221ec89ad5aa67 (patch) | |
tree | 8f31197e6e796da6d6cc1490647f85ebb4a7179a /Modules | |
parent | 7fc972a2aa041a978b8c4b1b58d6406100a2db8d (diff) | |
parent | 94dc6736bd4a72e9af36d4df1c337bd0db5fd69c (diff) | |
download | cpython-d03ce4ae3d71ba84e1e30cf0cf221ec89ad5aa67.zip cpython-d03ce4ae3d71ba84e1e30cf0cf221ec89ad5aa67.tar.gz cpython-d03ce4ae3d71ba84e1e30cf0cf221ec89ad5aa67.tar.bz2 |
Issue #17106: Fix a segmentation fault in io.TextIOWrapper when an underlying
stream or a decoder produces data of an unexpected type (i.e. when
io.TextIOWrapper initialized with text stream or use bytes-to-bytes codec).
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_io/textio.c | 76 |
1 files changed, 48 insertions, 28 deletions
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index ffaa945..cff9c6e 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -257,6 +257,25 @@ incrementalnewlinedecoder_dealloc(nldecoder_object *self) Py_TYPE(self)->tp_free((PyObject *)self); } +static int +check_decoded(PyObject *decoded) +{ + if (decoded == NULL) + return -1; + if (!PyUnicode_Check(decoded)) { + PyErr_Format(PyExc_TypeError, + "decoder should return a string result, not '%.200s'", + Py_TYPE(decoded)->tp_name); + Py_DECREF(decoded); + return -1; + } + if (PyUnicode_READY(decoded) < 0) { + Py_DECREF(decoded); + return -1; + } + return 0; +} + #define SEEN_CR 1 #define SEEN_LF 2 #define SEEN_CRLF 4 @@ -286,18 +305,9 @@ _PyIncrementalNewlineDecoder_decode(PyObject *_self, Py_INCREF(output); } - if (output == NULL) + if (check_decoded(output) < 0) return NULL; - if (!PyUnicode_Check(output)) { - PyErr_SetString(PyExc_TypeError, - "decoder should return a string result"); - goto error; - } - - if (PyUnicode_READY(output) == -1) - goto error; - output_len = PyUnicode_GET_LENGTH(output); if (self->pendingcr && (final || output_len > 0)) { /* Prefix output with CR */ @@ -1458,7 +1468,13 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) Py_DECREF(chunk_size); if (input_chunk == NULL) goto fail; - assert(PyBytes_Check(input_chunk)); + if (!PyBytes_Check(input_chunk)) { + PyErr_Format(PyExc_TypeError, + "underlying %s() should have returned a bytes object, " + "not '%.200s'", (self->has_read1 ? "read1": "read"), + Py_TYPE(input_chunk)->tp_name); + goto fail; + } nbytes = PyBytes_Size(input_chunk); eof = (nbytes == 0); @@ -1472,10 +1488,7 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) _PyIO_str_decode, input_chunk, eof ? Py_True : Py_False, NULL); } - /* TODO sanity check: isinstance(decoded_chars, unicode) */ - if (decoded_chars == NULL) - goto fail; - if (PyUnicode_READY(decoded_chars) == -1) + if (check_decoded(decoded_chars) < 0) goto fail; textiowrapper_set_decoded_chars(self, decoded_chars); nchars = PyUnicode_GET_LENGTH(decoded_chars); @@ -1493,7 +1506,14 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) PyObject *next_input = PyNumber_Add(dec_buffer, input_chunk); if (next_input == NULL) goto fail; - assert (PyBytes_Check(next_input)); + if (!PyBytes_Check(next_input)) { + PyErr_Format(PyExc_TypeError, + "decoder getstate() should have returned a bytes " + "object, not '%.200s'", + Py_TYPE(next_input)->tp_name); + Py_DECREF(next_input); + goto fail; + } Py_DECREF(dec_buffer); Py_CLEAR(self->snapshot); self->snapshot = Py_BuildValue("NN", dec_flags, next_input); @@ -1542,7 +1562,7 @@ textiowrapper_read(textio *self, PyObject *args) decoded = PyObject_CallMethodObjArgs( self->decoder, _PyIO_str_decode, bytes, Py_True, NULL); Py_DECREF(bytes); - if (decoded == NULL) + if (check_decoded(decoded) < 0) goto fail; result = textiowrapper_get_decoded_chars(self, -1); @@ -2151,7 +2171,14 @@ textiowrapper_seek(textio *self, PyObject *args) if (input_chunk == NULL) goto fail; - assert (PyBytes_Check(input_chunk)); + if (!PyBytes_Check(input_chunk)) { + PyErr_Format(PyExc_TypeError, + "underlying read() should have returned a bytes " + "object, not '%.200s'", + Py_TYPE(input_chunk)->tp_name); + Py_DECREF(input_chunk); + goto fail; + } self->snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk); if (self->snapshot == NULL) { @@ -2162,12 +2189,8 @@ textiowrapper_seek(textio *self, PyObject *args) decoded = _PyObject_CallMethodId(self->decoder, &PyId_decode, "Oi", input_chunk, (int)cookie.need_eof); - if (decoded == NULL) + if (check_decoded(decoded) < 0) goto fail; - if (PyUnicode_READY(decoded) == -1) { - Py_DECREF(decoded); - goto fail; - } textiowrapper_set_decoded_chars(self, decoded); @@ -2283,13 +2306,11 @@ textiowrapper_tell(textio *self, PyObject *args) Py_DECREF(_state); \ } while (0) - /* TODO: replace assert with exception */ #define DECODER_DECODE(start, len, res) do { \ PyObject *_decoded = _PyObject_CallMethodId( \ self->decoder, &PyId_decode, "y#", start, len); \ - if (_decoded == NULL) \ + if (check_decoded(_decoded) < 0) \ goto fail; \ - assert (PyUnicode_Check(_decoded)); \ res = PyUnicode_GET_LENGTH(_decoded); \ Py_DECREF(_decoded); \ } while (0) @@ -2370,9 +2391,8 @@ textiowrapper_tell(textio *self, PyObject *args) /* We didn't get enough decoded data; signal EOF to get more. */ PyObject *decoded = _PyObject_CallMethodId( self->decoder, &PyId_decode, "yi", "", /* final = */ 1); - if (decoded == NULL) + if (check_decoded(decoded) < 0) goto fail; - assert (PyUnicode_Check(decoded)); chars_decoded += PyUnicode_GET_LENGTH(decoded); Py_DECREF(decoded); cookie.need_eof = 1; |