(original) (raw)
changeset: 84557:5fa793ae36cc parent: 84555:6587fd3d89ae parent: 84556:fc7bab8a8618 user: Serhiy Storchaka storchaka@gmail.com date: Thu Jul 11 22:28:18 2013 +0300 files: Lib/test/test_marshal.py Misc/NEWS Python/marshal.c description: Issue #17872: Fix a segfault in marshal.load() when input stream returns more bytes than requested. diff -r 6587fd3d89ae -r 5fa793ae36cc Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py Thu Jul 11 22:00:57 2013 +0300 +++ b/Lib/test/test_marshal.py Thu Jul 11 22:28:18 2013 +0300 @@ -2,6 +2,7 @@ from test import support import array +import io import marshal import sys import unittest @@ -259,6 +260,17 @@ unicode_string = 'T' self.assertRaises(TypeError, marshal.loads, unicode_string) + def test_bad_reader(self): + class BadReader(io.BytesIO): + def read(self, n=-1): + b = super().read(n) + if n is not None and n > 4: + b += b' ' * 10**6 + return b + for value in (1.0, 1j, b'0123456789', '0123456789'): + self.assertRaises(ValueError, marshal.load, + BadReader(marshal.dumps(value))) + def _test_eof(self): data = marshal.dumps(("hello", "dolly", None)) for i in range(len(data)): diff -r 6587fd3d89ae -r 5fa793ae36cc Misc/NEWS --- a/Misc/NEWS Thu Jul 11 22:00:57 2013 +0300 +++ b/Misc/NEWS Thu Jul 11 22:28:18 2013 +0300 @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17872: Fix a segfault in marshal.load() when input stream returns + more bytes than requested. + - Issue #18338: `python --version` now prints version string to stdout, and not to stderr. Patch by Berker Peksag and Michael Dickens. diff -r 6587fd3d89ae -r 5fa793ae36cc Python/marshal.c --- a/Python/marshal.c Thu Jul 11 22:00:57 2013 +0300 +++ b/Python/marshal.c Thu Jul 11 22:28:18 2013 +0300 @@ -570,8 +570,17 @@ else { read = (int)PyBytes_GET_SIZE(data); if (read > 0) { - ptr = PyBytes_AS_STRING(data); - memcpy(s, ptr, read); + if (read > n) { + PyErr_Format(PyExc_ValueError, + "read() returned too much data: " + "%zd bytes requested, %zd returned", + n, read); + read = -1; + } + else { + ptr = PyBytes_AS_STRING(data); + memcpy(s, ptr, read); + } } } Py_DECREF(data); @@ -841,11 +850,13 @@ double dx; retval = NULL; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; dx = PyOS_string_to_double(buf, NULL, NULL); if (dx == -1.0 && PyErr_Occurred()) @@ -860,8 +871,6 @@ unsigned char buf[8]; double x; if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -881,21 +890,25 @@ Py_complex c; retval = NULL; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; c.real = PyOS_string_to_double(buf, NULL, NULL); if (c.real == -1.0 && PyErr_Occurred()) break; n = r_byte(p); - if (n == EOF || r_string(buf, n, p) != n) { + if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } + if (r_string(buf, n, p) != n) + break; buf[n] = '\0'; c.imag = PyOS_string_to_double(buf, NULL, NULL); if (c.imag == -1.0 && PyErr_Occurred()) @@ -910,8 +923,6 @@ unsigned char buf[8]; Py_complex c; if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -921,8 +932,6 @@ break; } if (r_string((char*)buf, 8, p) != 8) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -954,8 +963,6 @@ } if (r_string(PyBytes_AS_STRING(v), n, p) != n) { Py_DECREF(v); - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } @@ -986,8 +993,6 @@ } if (r_string(buffer, n, p) != n) { PyMem_DEL(buffer); - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } /storchaka@gmail.com