From 24c3e9b283da26093ca653fc6b441042fedec135 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 2 Sep 2019 12:57:51 +1000 Subject: [PATCH] py/modstruct: Fix struct.pack_into with unaligned offset of native type. Following the same fix for unpack. --- extmod/moductypes.c | 2 +- py/binary.c | 6 +++--- py/binary.h | 2 +- py/modstruct.c | 3 ++- tests/basics/struct_endian.py | 7 +++++++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/extmod/moductypes.c b/extmod/moductypes.c index d4c7611dfe..cf83f43e33 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -305,7 +305,7 @@ static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) { static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) { char struct_type = big_endian ? '>' : '<'; static const char type2char[16] = "BbHhIiQq------fd"; - mp_binary_set_val(struct_type, type2char[val_type], val, &p); + mp_binary_set_val(struct_type, type2char[val_type], val, p, &p); } static inline mp_uint_t get_aligned_basic(uint val_type, void *p) { diff --git a/py/binary.c b/py/binary.c index 9810e46600..dfd25018c1 100644 --- a/py/binary.c +++ b/py/binary.c @@ -250,14 +250,14 @@ void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t } } -void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) { +void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr) { byte *p = *ptr; mp_uint_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { - // Make pointer aligned - p = (byte*)MP_ALIGN(p, (size_t)align); + // Align p relative to p_base + p = p_base + (uintptr_t)MP_ALIGN(p - p_base, (size_t)align); if (MP_ENDIANNESS_LITTLE) { struct_type = '<'; } else { diff --git a/py/binary.h b/py/binary.h index 092b722886..ac24378d2c 100644 --- a/py/binary.h +++ b/py/binary.h @@ -39,7 +39,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index); void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in); void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val); mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr); -void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr); +void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr); long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src); void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val); diff --git a/py/modstruct.c b/py/modstruct.c index 957e4917b6..3e7d90ec13 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -180,6 +180,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c const char *fmt = mp_obj_str_get_str(fmt_in); char fmt_type = get_fmt_type(&fmt); + byte *p_base = p; size_t i; for (i = 0; i < n_args;) { mp_uint_t cnt = 1; @@ -204,7 +205,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c } else { // If we run out of args then we just finish; CPython would raise struct.error while (cnt-- && i < n_args) { - mp_binary_set_val(fmt_type, *fmt, args[i++], &p); + mp_binary_set_val(fmt_type, *fmt, args[i++], p_base, &p); } } fmt++; diff --git a/tests/basics/struct_endian.py b/tests/basics/struct_endian.py index ae32438245..91f5539c15 100644 --- a/tests/basics/struct_endian.py +++ b/tests/basics/struct_endian.py @@ -15,3 +15,10 @@ print(struct.unpack('h', memoryview(buf)[1:3])) print(struct.unpack_from('i', buf, 1)) print(struct.unpack_from('@i', buf, 1)) print(struct.unpack_from('@ii', buf, 1)) + +# pack_into with unaligned native type +buf = bytearray(b'>----<<<<<<<') +struct.pack_into('i', buf, 1, 0x30313233) +print(buf) +struct.pack_into('@ii', buf, 3, 0x34353637, 0x41424344) +print(buf)