[Python-checkins] cpython (merge 3.3 -> default): Issue #17872: Fix a segfault in marshal.load() when input stream returns

serhiy.storchaka python-checkins at python.org
Thu Jul 11 21:31:16 CEST 2013


http://hg.python.org/cpython/rev/5fa793ae36cc
changeset:   84557:5fa793ae36cc
parent:      84555:6587fd3d89ae
parent:      84556:fc7bab8a8618
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Thu Jul 11 22:28:18 2013 +0300
summary:
  Issue #17872: Fix a segfault in marshal.load() when input stream returns
more bytes than requested.

files:
  Lib/test/test_marshal.py |  12 +++++++++
  Misc/NEWS                |   3 ++
  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
--- 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 @@
         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 --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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 --git a/Python/marshal.c b/Python/marshal.c
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -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;
             }

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list