8000 py, gc: Zero out newly allocated blocks in the GC. · lurch/micropython@daab651 · GitHub
[go: up one dir, main page]

Skip to content

Commit daab651

Browse files
committed
py, gc: Zero out newly allocated blocks in the GC.
Also add some more debugging output to gc_dump_alloc_table(). Now that newly allocated heap is always zero'd, maybe we just make this a policy for the uPy API to keep it simple (ie any new implementation of memory allocation must zero all allocations). This follows the D language philosophy. Before this patch, a previously used memory block which had pointers in it may still retain those pointers if the new user of that block does not actually use the entire block. Eg, if I want 5 blocks worth of heap, I actually get 8 (round up to nearest 4). Then I never use the last 3, so they keep their old values, which may be pointers pointing to the heap, hence preventing GC. In rare (or maybe not that rare) cases, this leads to long, unintentional "linked lists" within the GC'd heap, filling it up completely. It's pretty rare, because you have to reuse exactly that memory which is part of this "linked list", and reuse it in just the right way. This should fix issue micropython#522, and might have something to do with issue micropython#510.
1 parent 5be40af commit daab651

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

py/gc.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,10 +366,17 @@ void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
366366
// get pointer to first block
367367
void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK);
368368

369+
// zero out the newly allocated blocks
370+
// This is needed because the blocks may have previously held pointers
371+
// to the heap and will not be set to something else if the caller
372+
// doesn't actually use the entire block. As such they will continue
373+
// to point to the heap and may prevent other blocks from being reclaimed.
374+
memset(ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK);
375+
369376
#if MICROPY_ENABLE_FINALISER
370377
if (has_finaliser) {
371-
// clear type pointer in case it is never set
372-
((mp_obj_base_t*)ret_ptr)->type = MP_OBJ_NULL;
378+
// clear type pointer in case it is never set (now done above in memset)
379+
//((mp_obj_base_t*)ret_ptr)->type = MP_OBJ_NULL;
373380
// set mp_obj flag only if it has a finaliser
374381
FTB_SET(start_block);
375382
}
@@ -523,6 +530,10 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
523530
assert(ATB_GET_KIND(bl) == AT_FREE);
524531
ATB_FREE_TO_TAIL(bl);
525532
}
533+
534+
// zero out the newly allocated blocks (see comment above in gc_alloc)
535+
memset(ptr_in + n_blocks * BYTES_PER_BLOCK, 0, (new_blocks - n_blocks) * BYTES_PER_BLOCK);
536+
526537
return ptr_in;
527538
}
528539

@@ -556,7 +567,7 @@ void gc_dump_info() {
556567
}
557568

558569
void gc_dump_alloc_table(void) {
559-
printf("GC memory layout:");
570+
printf("GC memory layout; from %p:", gc_pool_start);
560571
for (machine_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
561572
if (bl % 64 == 0) {
562573
printf("\n%04x: ", (uint)bl);
@@ -565,6 +576,18 @@ void gc_dump_alloc_table(void) {
565576
switch (ATB_GET_KIND(bl)) {
566577
case AT_FREE: c = '.'; break;
567578
case AT_HEAD: c = 'h'; break;
579+
/* this prints the uPy object type of the head block
580+
case AT_HEAD: {
581+
machine_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
582+
if (*ptr == (machine_uint_t)&mp_type_tuple) { c = 'T'; }
583+
else if (*ptr == (machine_uint_t)&mp_type_list) { c = 'L'; }
584+
else if (*ptr == (machine_uint_t)&mp_type_dict) { c = 'D'; }
585+
else if (*ptr == (machine_uint_t)&mp_type_float) { c = 'F'; }
586+
else if (*ptr == (machine_uint_t)&mp_type_fun_bc) { c = 'B'; }
587+
else { c = 'h'; }
588+
break;
589+
}
590+
*/
568591
case AT_TAIL: c = 't'; break;
569592
case AT_MARK: c = 'm'; break;
570593
}

py/malloc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,13 @@ void *m_malloc_with_finaliser(int num_bytes) {
8888

8989
void *m_malloc0(int num_bytes) {
9090
void *ptr = m_malloc(num_bytes);
91+
#if MICROPY_ENABLE_GC
92+
// the GC already zeros out all memory
93+
#else
9194
if (ptr != NULL) {
9295
memset(ptr, 0, num_bytes);
9396
}
97+
#endif
9498
return ptr;
9599
}
96100

0 commit comments

Comments
 (0)
0