From d75ff422972189232345108ecd2037ac148acda1 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 15 Sep 2021 10:54:48 -0500 Subject: [PATCH] unix/coverage: Add extra GC coverage test for ATB gap byte. The assertion that is added here (to gc.c) fails when running this new test if ALLOC_TABLE_GAP_BYTE is set to 0. Signed-off-by: Jeff Epler Signed-off-by: Damien George --- ports/unix/coverage.c | 37 ++++++++++++++++++++++++++++++++ py/gc.c | 3 +++ tests/unix/extra_coverage.py.exp | 2 ++ 3 files changed, 42 insertions(+) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 8b7fc7de67..f545674cee 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -1,4 +1,5 @@ #include +#include #include #include "py/obj.h" @@ -224,6 +225,42 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%p\n", gc_nbytes(NULL)); } + // GC initialisation and allocation stress test, to check the logic behind ALLOC_TABLE_GAP_BYTE + // (the following test should fail when ALLOC_TABLE_GAP_BYTE=0) + { + mp_printf(&mp_plat_print, "# GC part 2\n"); + + // check the GC is unlocked and save its state + assert(MP_STATE_THREAD(gc_lock_depth) == 0); + mp_state_mem_t mp_state_mem_orig = mp_state_ctx.mem; + + // perform the test + unsigned heap_size = 64 * MICROPY_BYTES_PER_GC_BLOCK; + for (unsigned j = 0; j < 256 * MP_BYTES_PER_OBJ_WORD; ++j) { + char *heap = calloc(heap_size, 1); + gc_init(heap, heap + heap_size); + + m_malloc(MICROPY_BYTES_PER_GC_BLOCK); + void *o = gc_alloc(MICROPY_BYTES_PER_GC_BLOCK, GC_ALLOC_FLAG_HAS_FINALISER); + ((mp_obj_base_t *)o)->type = NULL; // ensure type is cleared so GC doesn't look for finaliser + for (unsigned i = 0; i < heap_size / MICROPY_BYTES_PER_GC_BLOCK; ++i) { + void *p = m_malloc_maybe(MICROPY_BYTES_PER_GC_BLOCK); + if (!p) { + break; + } + *(void **)p = o; + o = p; + } + gc_collect(); + free(heap); + heap_size += MICROPY_BYTES_PER_GC_BLOCK / 16; + } + mp_printf(&mp_plat_print, "pass\n"); + + // restore the GC state (the original heap) + mp_state_ctx.mem = mp_state_mem_orig; + } + // tracked allocation { #define NUM_PTRS (8) diff --git a/py/gc.c b/py/gc.c index 99eacfbe6f..3c106fd671 100644 --- a/py/gc.c +++ b/py/gc.c @@ -297,6 +297,9 @@ STATIC void gc_mark_subtree(size_t block) n_blocks += 1; } while (ATB_GET_KIND(area, block + n_blocks) == AT_TAIL); + // check that the consecutive blocks didn't overflow past the end of the area + assert(area->gc_pool_start + (block + n_blocks) * BYTES_PER_BLOCK <= area->gc_pool_end); + // check this block's children void **ptrs = (void **)PTR_FROM_BLOCK(area, block); for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void *); i > 0; i--, ptrs++) { diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 2f8e37c5fe..ab6d497723 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -17,6 +17,8 @@ abc # GC 0 0 +# GC part 2 +pass # tracked allocation m_tracked_head = 0 0 1