FREE_AT_EXIT: Don't free main stack post-fork

When a forked process was started in a thread, this would result in a
double-free during the child process exit.

    RUBY_FREE_AT_EXIT=1 ./miniruby -e 'Thread.new { fork { } }.join; Process.waitpid'

This is because the main thread in the forked process was not the
initial VM thread, and the new thread's stack was freed as part of
objectspace iteration.

This change also allows rb_threadptr_root_fiber_release to run without
EC being available.
This commit is contained in:
John Hawthorn 2023-12-22 12:15:22 -08:00
Родитель 339978ef38
Коммит f1b7424cbe
2 изменённых файлов: 4 добавлений и 3 удалений

4
cont.c
Просмотреть файл

@ -2587,12 +2587,12 @@ rb_threadptr_root_fiber_release(rb_thread_t *th)
/* ignore. A root fiber object will free th->ec */
}
else {
rb_execution_context_t *ec = GET_EC();
rb_execution_context_t *ec = rb_current_execution_context(false);
VM_ASSERT(th->ec->fiber_ptr->cont.type == FIBER_CONTEXT);
VM_ASSERT(th->ec->fiber_ptr->cont.self == 0);
if (th->ec == ec) {
if (ec && th->ec == ec) {
rb_ractor_set_current_ec(th->ractor, NULL);
}
fiber_free(th->ec->fiber_ptr);

3
vm.c
Просмотреть файл

@ -3056,7 +3056,8 @@ ruby_vm_destruct(rb_vm_t *vm)
rb_objspace_free_objects(objspace);
rb_free_generic_iv_tbl_();
rb_free_default_rand_key();
if (th) {
if (th && vm->fork_gen == 0) {
/* If we have forked, main_thread may not be the initial thread */
xfree(stack);
ruby_mimfree(th);
}