]> granicus.if.org Git - gc/commitdiff
Fix assertion violation and partial overlapping in remove_roots_subregion
authorIvan Maidanski <ivmai@mail.ru>
Tue, 8 May 2018 17:17:48 +0000 (20:17 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 8 May 2018 17:17:48 +0000 (20:17 +0300)
(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.

mark_rts.c

index 2997024d3a4ce9437bb138f8501b9614905772d9..0cd7696696749e263403f97cf1ba05bf7639a8c0 100644 (file)
@@ -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 */