Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
gc: Do not finish lazy sweeps when freeing the object space
When freeing the object space from `ruby_vm_destruct`, we were
performing a `gc_rest_sweep` to wrap up any potentially undergoing lazy
sweeps.

This operation is extremely dangerous because it is performed without
a GVL (which has been removed previously in `ruby_vm_destruct`) and
without a main thread to operate with (which has been cleared previously
when freeing the main VM thread in `ruby_vm_destruct`). Since finishing
a lazy sweep on the heap can cause objects to be deallocated, if the
free function of any of these objects uses threading information, it
will segfault.

The builtin `Fiber` object (cont.c), for instance, accesses current
thread information with `GET_THREAD()` when being freed, and can
potentially segfault.  Any user defined T_DATA with a free callback
can also trigger segfaults, and likewise for any object in Rubyland
with a finalizer.

Because of the way that the MRI teardown process functions, the only way
that a lazy sweep can be underway when freeing the object space is if it
was triggered when calling the on-exit finalizers
(`rb_gc_call_finalizer_at_exit`). Before calling all the object
finalizers, `rb_objspace_call_finalizer` finishes any current lazy
sweeps. However, since the process of calling finalizers can allocate
more objects on the Ruby heap, it is possible for a call to `newobj` to
start another lazy sweep phase.

Hence, instead of finishing the lazy sweep when freeing the object
space, we attempt to finish it right after all the finalizers have been
called. This way, we can assert that no lazy sweeps and no object
deallocation will be performed after the main thread and the GVL have
been cleared.
  • Loading branch information
Vicent Marti committed Jan 23, 2015
commit 1ae74499395de2b8c2170d20f775ae0032e8cfb9
9 changes: 8 additions & 1 deletion gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,8 @@ static void heap_page_free(rb_objspace_t *objspace, struct heap_page *page);
void
rb_objspace_free(rb_objspace_t *objspace)
{
gc_rest_sweep(objspace);
if (is_lazy_sweeping(heap_eden))
rb_bug("lazy sweeping underway when freeing object space");

if (objspace->profile.records) {
free(objspace->profile.records);
Expand Down Expand Up @@ -2255,6 +2256,12 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)
st_free_table(finalizer_table);
finalizer_table = 0;
ATOMIC_SET(finalizing, 0);

/*
* finish any lazy sweeps that may have been started
* when finalizing the objects in the heap
*/
gc_rest_sweep(objspace);
}

static inline int
Expand Down