summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2013-02-03 15:07:32 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2013-02-03 15:07:32 (GMT)
commitd03ce4ae3d71ba84e1e30cf0cf221ec89ad5aa67 (patch)
tree8f31197e6e796da6d6cc1490647f85ebb4a7179a /Modules
parent7fc972a2aa041a978b8c4b1b58d6406100a2db8d (diff)
parent94dc6736bd4a72e9af36d4df1c337bd0db5fd69c (diff)
downloadcpython-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.c76
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;