From: Serhiy Storchaka Date: Wed, 19 Apr 2017 19:34:58 +0000 (+0300) Subject: [2.7] bpo-30061: Check if PyObject_Size()/PySequence_Size()/PyMapping_Size() (GH... X-Git-Tag: v2.7.14rc1~206 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=64aa4df8502ca5d0a8ffb767ff97f625625c758c;p=thirdparty%2FPython%2Fcpython.git [2.7] bpo-30061: Check if PyObject_Size()/PySequence_Size()/PyMapping_Size() (GH-1096) (GH-1180) (#1183) raised an error. (cherry picked from commit bf623ae8843dc30b28c574bec8d29fc14be59d86) (cherry picked from commit 680fea4) --- diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index fb91a2dbca41..caca0333e0d8 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -396,6 +396,22 @@ class IOTest(unittest.TestCase): with self.open(support.TESTFN, "r") as f: self.assertRaises(TypeError, f.readline, 5.3) + def test_readline_nonsizeable(self): + # Issue #30061 + # Crash when readline() returns an object without __len__ + class R(self.IOBase): + def readline(self): + return None + self.assertRaises((TypeError, StopIteration), next, R()) + + def test_next_nonsizeable(self): + # Issue #30061 + # Crash when next() returns an object without __len__ + class R(self.IOBase): + def next(self): + return None + self.assertRaises(TypeError, R().readlines, 1) + def test_raw_bytes_io(self): f = self.BytesIO() self.write_ops(f) diff --git a/Misc/NEWS b/Misc/NEWS index f2bd997e5dd5..29c5e98e3ec6 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -42,6 +42,11 @@ Extension Modules Library ------- +- bpo-30061: Fixed crashes in IOBase methods next() and readlines() when + readline() or next() respectively return non-sizeable object. + Fixed possible other errors caused by not checking results of PyObject_Size(), + PySequence_Size(), or PyMapping_Size(). + - bpo-30011: Fixed race condition in HTMLParser.unescape(). - bpo-30068: _io._IOBase.readlines will check if it's closed first when diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 066dc8edad6a..d813daf6cfb3 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -571,7 +571,8 @@ iobase_iternext(PyObject *self) if (line == NULL) return NULL; - if (PyObject_Size(line) == 0) { + if (PyObject_Size(line) <= 0) { + /* Error or empty */ Py_DECREF(line); return NULL; } @@ -618,6 +619,7 @@ iobase_readlines(PyObject *self, PyObject *args) } while (1) { + Py_ssize_t line_length; PyObject *line = PyIter_Next(it); if (line == NULL) { if (PyErr_Occurred()) { @@ -631,11 +633,14 @@ iobase_readlines(PyObject *self, PyObject *args) Py_DECREF(line); goto error; } - length += PyObject_Size(line); + line_length = PyObject_Size(line); Py_DECREF(line); - - if (length > hint) + if (line_length < 0) { + goto error; + } + if (line_length > hint - length) break; + length += line_length; } Py_DECREF(it); diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 871362800ef4..8901b42e41e8 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -1604,6 +1604,9 @@ mbstreamwriter_writelines(MultibyteStreamWriterObject *self, PyObject *lines) if (r == -1) return NULL; } + /* PySequence_Length() can fail */ + if (PyErr_Occurred()) + return NULL; Py_RETURN_NONE; } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index e73805fadfd3..ad505364bda9 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6077,7 +6077,7 @@ Set the groups of the current process to list."); static PyObject * posix_setgroups(PyObject *self, PyObject *groups) { - int i, len; + Py_ssize_t i, len; gid_t grouplist[MAX_GROUPS]; if (!PySequence_Check(groups)) { @@ -6085,6 +6085,9 @@ posix_setgroups(PyObject *self, PyObject *groups) return NULL; } len = PySequence_Size(groups); + if (len < 0) { + return NULL; + } if (len > MAX_GROUPS) { PyErr_SetString(PyExc_ValueError, "too many groups"); return NULL;