From 9d11bda9e8bea0f202165d649849daf63bff4465 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 18 May 2023 13:24:50 -0700 Subject: [PATCH] Fix memoryview.cast over sliced memoryview Fixes #4758 --- ports/unix/main.c | 2 +- py/objarray.c | 10 ++++++---- tests/basics/memoryview_cast.py | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 tests/basics/memoryview_cast.py diff --git a/ports/unix/main.c b/ports/unix/main.c index 5ebcf9193b..dcc1c68fe6 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -716,7 +716,7 @@ MP_NOINLINE int main_(int argc, char **argv) { } #if !MICROPY_VFS -uint mp_import_stat(const char *path) { +mp_import_stat_t mp_import_stat(const char *path) { struct stat st; if (stat(path, &st) == 0) { if (S_ISDIR(st.st_mode)) { diff --git a/py/objarray.c b/py/objarray.c index 518c3aba52..c4a9e7cec4 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -254,12 +254,14 @@ STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, STATIC mp_obj_t memoryview_cast(const mp_obj_t self_in, const mp_obj_t typecode_in) { mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); const char *typecode = mp_obj_str_get_str(typecode_in); - size_t element_size = mp_binary_get_size('@', typecode[0], NULL); - size_t bytelen = self->len * mp_binary_get_size('@', self->typecode & ~MP_OBJ_ARRAY_TYPECODE_FLAG_RW, NULL); - if (bytelen % element_size != 0) { + size_t new_element_size = mp_binary_get_size('@', typecode[0], NULL); + size_t old_element_size = mp_binary_get_size('@', self->typecode & ~MP_OBJ_ARRAY_TYPECODE_FLAG_RW, NULL); + size_t bytelen = self->len * old_element_size; + if (bytelen % new_element_size != 0) { mp_raise_TypeError(MP_ERROR_TEXT("memoryview: length is not a multiple of itemsize")); } - mp_obj_array_t *result = MP_OBJ_TO_PTR(mp_obj_new_memoryview(*typecode, bytelen / element_size, self->items)); + mp_obj_array_t *result = MP_OBJ_TO_PTR(mp_obj_new_memoryview(*typecode, bytelen / new_element_size, self->items)); + result->memview_offset = (self->memview_offset * old_element_size) / new_element_size; // test if the object can be written to if (self->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW) { diff --git a/tests/basics/memoryview_cast.py b/tests/basics/memoryview_cast.py new file mode 100644 index 0000000000..24c04e8e5a --- /dev/null +++ b/tests/basics/memoryview_cast.py @@ -0,0 +1,21 @@ +try: + memoryview(b'a').cast +except: + print("SKIP") + raise SystemExit + +b = bytearray(range(16)) + +def print_memview(mv): + print(", ".join(hex(v) for v in mv)) + +mv = memoryview(b) +print_memview(mv) +print_memview(mv[4:]) + +words = mv.cast("I") +print_memview(words) +print_memview(mv[4:].cast("I")) +print_memview(words[1:]) + +print_memview(words.cast("B"))