From ab69c0069c99e19d2eff0c3dafdf285c6b46715d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 19 May 2020 15:18:26 +0200 Subject: [PATCH] [python] Fix alignement issues in MicroPython::collectRootsAtAddress --- python/port/port.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/python/port/port.cpp b/python/port/port.cpp index 6ae0c36c9..0a2ebc4b7 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -155,12 +155,28 @@ void MicroPython::registerScriptProvider(ScriptProvider * s) { } void MicroPython::collectRootsAtAddress(char * address, int byteLength) { - /* All addresses stored on the stack are aligned on sizeof(void *), as - * asserted. This is a consequence of the alignment requirements of compilers - * (Cf http://www.catb.org/esr/structure-packing/). */ - assert(((unsigned long)address) % ((unsigned long)sizeof(void *)) == 0); - assert(byteLength % sizeof(void *) == 0); - gc_collect_root((void **)address, byteLength / sizeof(void *)); + /* The given address is not necessarily aligned on sizeof(void *). However, + * any pointer stored in the range [address, address + byteLength] will be + * aligned on sizeof(void *). This is a consequence of the alignment + * requirements of compilers (Cf http://www.catb.org/esr/structure-packing/). + * Micropython gc_collect_root scans looking for pointers jumping every + * sizeof(void *). It has to be provided with a sizeof(uintptr_t)-aligned + * address. */ + // Compute the aligned address + // 0b000...00011 with 2 (or 3 for x64 arch) 1s + uintptr_t bitMaskOnes = sizeof(uintptr_t) - 1; + // 0b111...11100 with sizeof(uintptr_t)-1 0s + uintptr_t bitMaskZeros = ~bitMaskOnes; + uintptr_t alignedAddress = reinterpret_cast(address) & bitMaskZeros; + /* Increase the length consequently with the new alignment + * (We don't need to increase the byteLength to a sizeof(uintptr_t)-aligned + * lenght because no pointer can be stored on less than sizeof(uintptr_t) + * bytes.) */ + int alignedByteLength = byteLength; + alignedByteLength += reinterpret_cast(address) & bitMaskOnes; + + assert(alignedAddress % ((uintptr_t)sizeof(uintptr_t)) == 0); + gc_collect_root((void **)alignedAddress, byteLength / sizeof(uintptr_t)); } KDColor MicroPython::ColorParser::ParseColor(mp_obj_t input, ColorMode ColorMode){