[Python-checkins] cpython (3.4): Issue #22668: Ensure that format strings survive slicing after casting.

stefan.krah python-checkins at python.org
Thu Jan 29 14:35:14 CET 2015


https://hg.python.org/cpython/rev/e9c1fca50b46
changeset:   94372:e9c1fca50b46
branch:      3.4
parent:      94370:c4fd6df9aea6
user:        Stefan Krah <skrah at bytereef.org>
date:        Thu Jan 29 14:27:23 2015 +0100
summary:
  Issue #22668: Ensure that format strings survive slicing after casting.

files:
  Include/memoryobject.h      |   4 +-
  Lib/test/test_memoryview.py |  19 ++++++++
  Objects/memoryobject.c      |  56 +++++++++++++++++++++++-
  3 files changed, 73 insertions(+), 6 deletions(-)


diff --git a/Include/memoryobject.h b/Include/memoryobject.h
--- a/Include/memoryobject.h
+++ b/Include/memoryobject.h
@@ -45,7 +45,7 @@
 } _PyManagedBufferObject;
 
 
-/* static storage used for casting between formats */
+/* deprecated, removed in 3.5 */
 #define _Py_MEMORYVIEW_MAX_FORMAT 3 /* must be >= 3 */
 
 /* memoryview state flags */
@@ -62,7 +62,7 @@
     int flags;                    /* state flags */
     Py_ssize_t exports;           /* number of buffer re-exports */
     Py_buffer view;               /* private copy of the exporter's view */
-    char format[_Py_MEMORYVIEW_MAX_FORMAT]; /* used for casting */
+    char format[_Py_MEMORYVIEW_MAX_FORMAT]; /* deprecated, removed in 3.5 */
     PyObject *weakreflist;
     Py_ssize_t ob_array[1];       /* shape, strides, suboffsets */
 } PyMemoryViewObject;
diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py
--- a/Lib/test/test_memoryview.py
+++ b/Lib/test/test_memoryview.py
@@ -360,6 +360,25 @@
             self.assertEqual(list(reversed(m)), aslist)
             self.assertEqual(list(reversed(m)), list(m[::-1]))
 
+    def test_issue22668(self):
+        m = memoryview(bytes(range(8)))
+        b = m.cast('H')
+        c = b[0:2]
+        d = memoryview(b)
+
+        del b
+    
+        self.assertEqual(c[0], 256)
+        self.assertEqual(d[0], 256)
+        self.assertEqual(c.format, "H")
+        self.assertEqual(d.format, "H")
+    
+        _ = m.cast('I')
+        self.assertEqual(c[0], 256)
+        self.assertEqual(d[0], 256)
+        self.assertEqual(c.format, "H")
+        self.assertEqual(d.format, "H")
+
 
 # Variations on source objects for the buffer: bytes-like objects, then arrays
 # with itemsize > 1.
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
--- a/Objects/memoryobject.c
+++ b/Objects/memoryobject.c
@@ -1135,6 +1135,51 @@
     return -1;
 }
 
+Py_LOCAL_INLINE(char *)
+get_native_fmtstr(const char *fmt)
+{
+    int at = 0;
+
+    if (fmt[0] == '@') {
+        at = 1;
+        fmt++;
+    }
+    if (fmt[0] == '\0' || fmt[1] != '\0') {
+        return NULL;
+    }
+
+#define RETURN(s) do { return at ? "@" s : s; } while (0)
+
+    switch (fmt[0]) {
+    case 'c': RETURN("c");
+    case 'b': RETURN("b");
+    case 'B': RETURN("B");
+    case 'h': RETURN("h");
+    case 'H': RETURN("H");
+    case 'i': RETURN("i");
+    case 'I': RETURN("I");
+    case 'l': RETURN("l");
+    case 'L': RETURN("L");
+    #ifdef HAVE_LONG_LONG
+    case 'q': RETURN("q");
+    case 'Q': RETURN("Q");
+    #endif
+    case 'n': RETURN("n");
+    case 'N': RETURN("N");
+    case 'f': RETURN("f");
+    case 'd': RETURN("d");
+    #ifdef HAVE_C99_BOOL
+    case '?': RETURN("?");
+    #else
+    case '?': RETURN("?");
+    #endif
+    case 'P': RETURN("P");
+    }
+
+    return NULL;
+}
+
+
 /* Cast a memoryview's data type to 'format'. The input array must be
    C-contiguous. At least one of input-format, output-format must have
    byte size. The output array is 1-D, with the same byte length as the
@@ -1184,10 +1229,13 @@
         goto out;
     }
 
-    strncpy(mv->format, PyBytes_AS_STRING(asciifmt),
-            _Py_MEMORYVIEW_MAX_FORMAT);
-    mv->format[_Py_MEMORYVIEW_MAX_FORMAT-1] = '\0';
-    view->format = mv->format;
+    view->format = get_native_fmtstr(PyBytes_AS_STRING(asciifmt));
+    if (view->format == NULL) {
+        /* NOT_REACHED: get_native_fmtchar() already validates the format. */
+        PyErr_SetString(PyExc_RuntimeError,
+            "memoryview: internal error");
+        goto out;
+    }
     view->itemsize = itemsize;
 
     view->ndim = 1;

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


More information about the Python-checkins mailing list