From cb0e9e86609c837e02957dd8132b64d83506b15a Mon Sep 17 00:00:00 2001 From: Peter Bex Date: Fri, 30 Jun 2017 15:28:08 +0200 Subject: [PATCH 1/2] Fix unpersistability sanity check for symbol GC The sanity check we do just before dropping symbols from the symbol table will ensure that the "bound value" slot of a symbol is either empty or contains the symbol itself. If either is violated, the assertion check fails. This is correct, but keywords may have been moved by the GC and replaced with forwarding pointers. This means the symbol value slot could contain a forwarding pointer, which is definitely _not_ equal to the symbol itself. To fix this, before performing our sanity checks, we now fix up any forwarding pointers in the symbol's value. --- runtime.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/runtime.c b/runtime.c index 64020e24..311a1be7 100644 --- a/runtime.c +++ b/runtime.c @@ -4132,6 +4132,25 @@ C_regparm void C_fcall update_locative_table(int mode) if(mode != GC_REALLOC) locative_table_count = hi; } +static C_regparm void fixup_symbol_forwards(C_word sym) +{ + C_word val, h; + int i, s = C_header_size(sym); /* 3 */ + + for (i = 0; i < s; i++) { + val = C_block_item(sym, i); + if (!C_immediatep(val)) { + h = C_block_header(val); + + while(is_fptr(h)) { + val = fptr_to_ptr(h); + h = C_block_header(val); + } + C_set_block_item(sym, i, val); + } + } +} + C_regparm void C_fcall update_symbol_tables(int mode) { int weakn = 0, i; @@ -4159,17 +4178,11 @@ C_regparm void C_fcall update_symbol_tables(int mode) #ifdef DEBUGBUILD /* Detect inconsistencies before dropping / keeping the symbol */ + fixup_symbol_forwards(sym); { C_word str = C_symbol_name(sym); int str_perm; - h = C_block_header(str); - - while(is_fptr(h)) { - str = fptr_to_ptr(h); - h = C_block_header(str); - } - str_perm = !C_in_stackp(str) && !C_in_heapp(str) && !C_in_scratchspacep(str) && (mode == GC_REALLOC ? !C_in_new_heapp(str) : 1); @@ -4196,7 +4209,10 @@ C_regparm void C_fcall update_symbol_tables(int mode) if(last) C_set_block_item(last, 1, C_block_item(bucket,1)); else stp->table[ i ] = C_block_item(bucket,1); +#ifndef NDEBUG + fixup_symbol_forwards(sym); assert(!C_persistable_symbol(sym)); +#endif ++weakn; } else { C_set_block_item(bucket,0,sym); /* Might have moved */ -- 2.11.0