diff options
-rw-r--r-- | Lib/test/test_marshal.py | 12 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Python/marshal.c | 35 |
3 files changed, 35 insertions, 15 deletions
diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 292746b..ab06237 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -2,6 +2,7 @@ from test import support import array +import io import marshal import sys import unittest @@ -259,6 +260,17 @@ class BugsTestCase(unittest.TestCase): 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)): @@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1? 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 --git a/Python/marshal.c b/Python/marshal.c index a45e148..1997e19 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -570,8 +570,17 @@ r_string(char *s, Py_ssize_t n, RFILE *p) 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 @@ r_object(RFILE *p) 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 @@ r_object(RFILE *p) 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 @@ r_object(RFILE *p) 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 @@ r_object(RFILE *p) 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 @@ r_object(RFILE *p) 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 @@ r_object(RFILE *p) } 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 @@ r_object(RFILE *p) } if (r_string(buffer, n, p) != n) { PyMem_DEL(buffer); - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); retval = NULL; break; } |