From: Ivan Maidanski Date: Tue, 8 May 2018 17:17:48 +0000 (+0300) Subject: Fix assertion violation and partial overlapping in remove_roots_subregion X-Git-Tag: v8.0.0~195 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e849b45c;p=gc Fix assertion violation and partial overlapping in remove_roots_subregion (fix of commit 38d194a) Issue #218 (bdwgc). * mark_rts.c [USE_PROC_FOR_LIBRARIES] (GC_remove_roots_subregion): Update comment; add assertion that b and e pointers are word-aligned; handle also cases of partial overlapping with the existing roots; call GC_rebuild_root_index() only when needed; update existing root instead of removing old and adding new one (where possible); move newly static added root to precede dynamic ones (if any); process all static roots even if an intersection is already found. --- diff --git a/mark_rts.c b/mark_rts.c index 2997024d..0cd76966 100644 --- a/mark_rts.c +++ b/mark_rts.c @@ -379,15 +379,16 @@ STATIC void GC_remove_tmp_roots(void) #endif /* !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) */ #ifdef USE_PROC_FOR_LIBRARIES - /* If there is a static root containing [b,e) then replace this root */ - /* [r_start,r_end) with roots [r_start,b) and [e,r_end). */ - /* It is assumed that GC_remove_tmp_roots() is called before this */ - /* function is called repeatedly by GC_register_map_entries(). */ + /* Remove given range from every static root which intersects with */ + /* the range. It is assumed GC_remove_tmp_roots is called before */ + /* this function is called repeatedly by GC_register_map_entries. */ GC_INNER void GC_remove_roots_subregion(ptr_t b, ptr_t e) { int i; + GC_bool rebuild = FALSE; GC_ASSERT(I_HOLD_LOCK()); + GC_ASSERT((word)b % sizeof(word) == 0 && (word)e % sizeof(word) == 0); for (i = 0; i < n_root_sets; i++) { ptr_t r_start, r_end; @@ -403,21 +404,56 @@ STATIC void GC_remove_tmp_roots(void) } r_start = GC_static_roots[i].r_start; r_end = GC_static_roots[i].r_end; - if (EXPECT((word)r_start <= (word)b && (word)e <= (word)r_end, FALSE)) { + if (!EXPECT((word)e <= (word)r_start || (word)r_end <= (word)b, TRUE)) { # ifdef DEBUG_ADD_DEL_ROOTS GC_log_printf("Removing %p .. %p from root section %d (%p .. %p)\n", (void *)b, (void *)e, i, (void *)r_start, (void *)r_end); # endif - GC_remove_root_at_pos(i); - GC_rebuild_root_index(); - if ((word)r_start < (word)b) - GC_add_roots_inner(r_start, b, FALSE); - if ((word)e < (word)r_end) - GC_add_roots_inner(e, r_end, FALSE); - break; + if ((word)r_start < (word)b) { + GC_root_size -= r_end - b; + GC_static_roots[i].r_end = b; + /* No need to rebuild as hash does not use r_end value. */ + if ((word)e < (word)r_end) { + int j; + + if (rebuild) { + GC_rebuild_root_index(); + rebuild = FALSE; + } + GC_add_roots_inner(e, r_end, FALSE); /* updates n_root_sets */ + for (j = i + 1; j < n_root_sets; j++) + if (GC_static_roots[j].r_tmp) + break; + if (j < n_root_sets-1 && !GC_static_roots[n_root_sets-1].r_tmp) { + /* Exchange the roots to have all temporary ones at the end. */ + ptr_t tmp_r_start = GC_static_roots[j].r_start; + ptr_t tmp_r_end = GC_static_roots[j].r_end; + + GC_static_roots[j].r_start = + GC_static_roots[n_root_sets-1].r_start; + GC_static_roots[j].r_end = GC_static_roots[n_root_sets-1].r_end; + GC_static_roots[j].r_tmp = FALSE; + GC_static_roots[n_root_sets-1].r_start = tmp_r_start; + GC_static_roots[n_root_sets-1].r_end = tmp_r_end; + GC_static_roots[n_root_sets-1].r_tmp = TRUE; + rebuild = TRUE; + } + } + } else { + if ((word)e < (word)r_end) { + GC_root_size -= e - r_start; + GC_static_roots[i].r_start = e; + } else { + GC_remove_root_at_pos(i); + i--; + } + rebuild = TRUE; + } } } + if (rebuild) + GC_rebuild_root_index(); } #endif /* USE_PROC_FOR_LIBRARIES */