]> granicus.if.org Git - python/commitdiff
Issue #17872: Fix a segfault in marshal.load() when input stream returns
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 11 Jul 2013 19:28:18 +0000 (22:28 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Thu, 11 Jul 2013 19:28:18 +0000 (22:28 +0300)
more bytes than requested.

1  2 
Lib/test/test_marshal.py
Misc/NEWS
Python/marshal.c

index 292746bd58cd51fc35a4b85bff2d308f1868b075,7e37f39c6a74d94a1bda3523d7730b72af6bb8ce..ab062370641d0ea0cc8ce74dcb822e823a0c3444
@@@ -259,11 -280,17 +260,22 @@@ 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)):
 +            self.assertRaises(EOFError, marshal.loads, data[0: i])
 +
  LARGE_SIZE = 2**31
  pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4
  
diff --cc Misc/NEWS
index ea5a287f3e4642b5f7022be18e27215e491752de,3ff4d3e35f28b39377e48fe3025b5898437a9063..4cfe4f8fb18f94f1a720a4e34e1f14f3bd266de2
+++ b/Misc/NEWS
@@@ -10,9 -12,9 +10,12 @@@ 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.
 +
  - Issue #18426: Fix NULL pointer dereference in C extension import when
    PyModule_GetDef() returns an error.
  
index a45e148ff9d80b068cba33819c3ef33f090a53f3,a0e527fc8313cf4d474a322ca5e1c7371cc1a3d7..1997e1964f20531b25c16e9ee351b3265cade00b
@@@ -568,10 -488,19 +568,19 @@@ r_string(char *s, Py_ssize_t n, RFILE *
                               data->ob_type->tp_name);
              }
              else {
 -                read = PyBytes_GET_SIZE(data);
 +                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);
@@@ -978,26 -871,13 +985,24 @@@ r_object(RFILE *p
              retval = NULL;
              break;
          }
 -        buffer = PyMem_NEW(char, n);
 -        if (buffer == NULL) {
 -            retval = PyErr_NoMemory();
 -            break;
 -        }
 -        if (r_string(buffer, n, p) != n) {
 +        if (n != 0) {
 +            buffer = PyMem_NEW(char, n);
 +            if (buffer == NULL) {
 +                retval = PyErr_NoMemory();
 +                break;
 +            }
 +            if (r_string(buffer, n, p) != n) {
 +                PyMem_DEL(buffer);
-                 PyErr_SetString(PyExc_EOFError,
-                     "EOF read where object expected");
 +                retval = NULL;
 +                break;
 +            }
 +            v = PyUnicode_DecodeUTF8(buffer, n, "surrogatepass");
              PyMem_DEL(buffer);
 +        }
 +        else {
 +            v = PyUnicode_New(0, 0);
 +        }
 +        if (v == NULL) {
              retval = NULL;
              break;
          }