File tree Expand file tree Collapse file tree 5 files changed +78
-9
lines changed
Expand file tree Collapse file tree 5 files changed +78
-9
lines changed Original file line number Diff line number Diff line change @@ -485,6 +485,12 @@ Changes in the Python API
485485Changes in the C API
486486--------------------
487487
488+ * The undocumented :c:member: `~PyMemoryViewObject.format ` member of the
489+ (non-public) :c:type: `PyMemoryViewObject ` structure has been removed.
490+
491+ All extensions relying on the relevant parts in ``memoryobject.h ``
492+ must be rebuilt.
493+
488494* The :c:type: `PyMemAllocator ` structure was renamed to
489495 :c:type: `PyMemAllocatorEx ` and a new ``calloc `` field was added.
490496
Original file line number Diff line number Diff line change @@ -45,9 +45,6 @@ typedef struct {
4545} _PyManagedBufferObject ;
4646
4747
48- /* static storage used for casting between formats */
49- #define _Py_MEMORYVIEW_MAX_FORMAT 3 /* must be >= 3 */
50-
5148/* memoryview state flags */
5249#define _Py_MEMORYVIEW_RELEASED 0x001 /* access to master buffer blocked */
5350#define _Py_MEMORYVIEW_C 0x002 /* C-contiguous layout */
@@ -62,7 +59,6 @@ typedef struct {
6259 int flags ; /* state flags */
6360 Py_ssize_t exports ; /* number of buffer re-exports */
6461 Py_buffer view ; /* private copy of the exporter's view */
65- char format [_Py_MEMORYVIEW_MAX_FORMAT ]; /* used for casting */
6662 PyObject * weakreflist ;
6763 Py_ssize_t ob_array [1 ]; /* shape, strides, suboffsets */
6864} PyMemoryViewObject ;
Original file line number Diff line number Diff line change @@ -360,6 +360,25 @@ def test_reversed(self):
360360 self .assertEqual (list (reversed (m )), aslist )
361361 self .assertEqual (list (reversed (m )), list (m [::- 1 ]))
362362
363+ def test_issue22668 (self ):
364+ m = memoryview (bytes (range (8 )))
365+ b = m .cast ('H' )
366+ c = b [0 :2 ]
367+ d = memoryview (b )
368+
369+ del b
370+
371+ self .assertEqual (c [0 ], 256 )
372+ self .assertEqual (d [0 ], 256 )
373+ self .assertEqual (c .format , "H" )
374+ self .assertEqual (d .format , "H" )
375+
376+ _ = m .cast ('I' )
377+ self .assertEqual (c [0 ], 256 )
378+ self .assertEqual (d [0 ], 256 )
379+ self .assertEqual (c .format , "H" )
380+ self .assertEqual (d .format , "H" )
381+
363382
364383# Variations on source objects for the buffer: bytes-like objects, then arrays
365384# with itemsize > 1.
Original file line number Diff line number Diff line change @@ -965,7 +965,7 @@ def get_gen(): yield 1
965965 check (int (PyLong_BASE ** 2 - 1 ), vsize ('' ) + 2 * self .longdigit )
966966 check (int (PyLong_BASE ** 2 ), vsize ('' ) + 3 * self .longdigit )
967967 # memoryview
968- check (memoryview (b'' ), size ('Pnin 2P2n2i5P 3cPn ' ))
968+ check (memoryview (b'' ), size ('Pnin 2P2n2i5P Pn ' ))
969969 # module
970970 check (unittest , size ('PnPPP' ))
971971 # None
Original file line number Diff line number Diff line change @@ -1132,6 +1132,51 @@ get_native_fmtchar(char *result, const char *fmt)
11321132 return -1 ;
11331133}
11341134
1135+ Py_LOCAL_INLINE (char * )
1136+ get_native_fmtstr (const char * fmt )
1137+ {
1138+ int at = 0 ;
1139+
1140+ if (fmt [0 ] == '@' ) {
1141+ at = 1 ;
1142+ fmt ++ ;
1143+ }
1144+ if (fmt [0 ] == '\0' || fmt [1 ] != '\0' ) {
1145+ return NULL ;
1146+ }
1147+
1148+ #define RETURN (s ) do { return at ? "@" s : s; } while (0)
1149+
1150+ switch (fmt [0 ]) {
1151+ case 'c' : RETURN ("c" );
1152+ case 'b' : RETURN ("b" );
1153+ case 'B' : RETURN ("B" );
1154+ case 'h' : RETURN ("h" );
1155+ case 'H' : RETURN ("H" );
1156+ case 'i' : RETURN ("i" );
1157+ case 'I' : RETURN ("I" );
1158+ case 'l' : RETURN ("l" );
1159+ case 'L' : RETURN ("L" );
1160+ #ifdef HAVE_LONG_LONG
1161+ case 'q' : RETURN ("q" );
1162+ case 'Q' : RETURN ("Q" );
1163+ #endif
1164+ case 'n' : RETURN ("n" );
1165+ case 'N' : RETURN ("N" );
1166+ case 'f' : RETURN ("f" );
1167+ case 'd' : RETURN ("d" );
1168+ #ifdef HAVE_C99_BOOL
1169+ case '?' : RETURN ("?" );
1170+ #else
1171+ case '?' : RETURN ("?" );
1172+ #endif
1173+ case 'P' : RETURN ("P" );
1174+ }
1175+
1176+ return NULL ;
1177+ }
1178+
1179+
11351180/* Cast a memoryview's data type to 'format'. The input array must be
11361181 C-contiguous. At least one of input-format, output-format must have
11371182 byte size. The output array is 1-D, with the same byte length as the
@@ -1181,10 +1226,13 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
11811226 goto out ;
11821227 }
11831228
1184- strncpy (mv -> format , PyBytes_AS_STRING (asciifmt ),
1185- _Py_MEMORYVIEW_MAX_FORMAT );
1186- mv -> format [_Py_MEMORYVIEW_MAX_FORMAT - 1 ] = '\0' ;
1187- view -> format = mv -> format ;
1229+ view -> format = get_native_fmtstr (PyBytes_AS_STRING (asciifmt ));
1230+ if (view -> format == NULL ) {
1231+ /* NOT_REACHED: get_native_fmtchar() already validates the format. */
1232+ PyErr_SetString (PyExc_RuntimeError ,
1233+ "memoryview: internal error" );
1234+ goto out ;
1235+ }
11881236 view -> itemsize = itemsize ;
11891237
11901238 view -> ndim = 1 ;
You can’t perform that action at this time.
0 commit comments