Skip to content

Commit a1d3ee3

Browse files
committed
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).
1 parent 5d9b816 commit a1d3ee3

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

py/gc.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,21 @@ void gc_init(void *start, void *end) {
126126
gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
127127
#endif
128128

129-
130129
gc_alloc_table_start = (byte*)start;
131130

132131
#if MICROPY_ENABLE_FINALISER
133-
mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB) / BLOCKS_PER_FTB;
132+
mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
134133
gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len;
135134
#endif
136135

137136
mp_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
138137
gc_pool_start = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
139138
gc_pool_end = (mp_uint_t*)end;
140139

140+
#if MICROPY_ENABLE_FINALISER
141+
assert((byte*)gc_pool_start >= gc_finaliser_table_start + gc_finaliser_table_byte_len);
142+
#endif
143+
141144
// clear ATBs
142145
memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);
143146

0 commit comments

Comments
 (0)