From a1d3ee376c25c0842096535c38e651431028d1b8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 8 Aug 2014 12:33:49 +0100 Subject: [PATCH] py: Fix bug where GC finaliser table was not completely zeroed out. This was a nasty bug to track down. It only had consequences when the heap size was just the right size to expose the rounding error in the calculation of the finaliser table size. And, a script had to allocate a small (1 or 2 cell) object at the very end of the heap. And, this object must not have a finaliser. And, the initial state of the heap must have been all bits set to 1. All these conspire on the pyboard, but only if your run the script fresh (so unused memory is all 1's), and if your script allocates a lot of small objects (eg 2-char strings that are not interned). --- py/gc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/py/gc.c b/py/gc.c index 802c1b1edc..39dcd3c1d8 100644 --- a/py/gc.c +++ b/py/gc.c @@ -126,11 +126,10 @@ void gc_init(void *start, void *end) { gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK); #endif - gc_alloc_table_start = (byte*)start; #if MICROPY_ENABLE_FINALISER - mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB) / BLOCKS_PER_FTB; + mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB; gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len; #endif @@ -138,6 +137,10 @@ void gc_init(void *start, void *end) { gc_pool_start = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK); gc_pool_end = (mp_uint_t*)end; +#if MICROPY_ENABLE_FINALISER + assert((byte*)gc_pool_start >= gc_finaliser_table_start + gc_finaliser_table_byte_len); +#endif + // clear ATBs memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);