From 57c26241c38831db362493a21ce1fc691186465f Mon Sep 17 00:00:00 2001 From: Ivan Maidanski Date: Mon, 7 May 2018 11:05:15 +0300 Subject: [PATCH] Fix infinite restarting of mark_some when a static root disappeared (Linux) (a cherry-pick of commit 67338bbd from 'release-7_6') Issue #218 (bdwgc). * dyn_load.c [USE_PROC_FOR_LIBRARIES] (GC_register_map_entries): Call GC_remove_roots_subregion for each region which has prot starting with "---"; add comment. * include/private/gc_priv.h [USE_PROC_FOR_LIBRARIES] (GC_remove_roots_subregion): Declare function. * mark_rts.c [USE_PROC_FOR_LIBRARIES] (GC_remove_roots_subregion): Implement (including partial overlapping). --- dyn_load.c | 4 ++ include/private/gc_priv.h | 3 ++ mark_rts.c | 79 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/dyn_load.c b/dyn_load.c index 52b7470a..707ff766 100644 --- a/dyn_load.c +++ b/dyn_load.c @@ -366,6 +366,10 @@ STATIC word GC_register_map_entries(char *maps) } if (start < end) GC_add_roots_inner((char *)start, (char *)end, TRUE); + } else if (prot[0] == '-' && prot[1] == '-' && prot[2] == '-') { + /* Even roots added statically might disappear partially */ + /* (e.g. the roots added by INCLUDE_LINUX_THREAD_DESCR). */ + GC_remove_roots_subregion(start, end); } } return 1; diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index 103999eb..4195e4ab 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -1577,6 +1577,9 @@ GC_INNER void GC_set_fl_marks(ptr_t p); /* set. Abort if not. */ #endif void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp); +#ifdef USE_PROC_FOR_LIBRARIES + GC_INNER void GC_remove_roots_subregion(ptr_t b, ptr_t e); +#endif GC_INNER void GC_exclude_static_roots_inner(void *start, void *finish); #if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \ || defined(CYGWIN32) || defined(PCR) diff --git a/mark_rts.c b/mark_rts.c index bf8ffc6c..02c4cafd 100644 --- a/mark_rts.c +++ b/mark_rts.c @@ -330,6 +330,85 @@ STATIC void GC_remove_tmp_roots(void) } #endif /* !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) */ +#ifdef USE_PROC_FOR_LIBRARIES + /* 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; + + if (GC_static_roots[i].r_tmp) { + /* The remaining roots are skipped as they are all temporary. */ +# ifdef GC_ASSERTIONS + int j; + for (j = i + 1; j < n_root_sets; j++) { + GC_ASSERT(GC_static_roots[j].r_tmp); + } +# endif + break; + } + r_start = GC_static_roots[i].r_start; + r_end = GC_static_roots[i].r_end; + 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 + 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 */ + #if (defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)) \ && !defined(NO_DEBUGGING) /* Not used at present (except for, may be, debugging purpose). */ -- 2.40.0