summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hawthorn <[email protected]>2023-12-22 12:15:22 -0800
committerJohn Hawthorn <[email protected]>2023-12-22 18:07:22 -0800
commitf1b7424cbed00a27532a053949f524eaaf4be1ba (patch)
treedab869a7d6175e5c100682aa74f1d5aa7d7e68b4
parent339978ef3869acb2ff877451381a80ee4b548bfb (diff)
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.
-rw-r--r--cont.c4
-rw-r--r--vm.c3
2 files changed, 4 insertions, 3 deletions
diff --git a/cont.c b/cont.c
index e345ac42c1..2b60860edd 100644
--- a/cont.c
+++ b/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);
diff --git a/vm.c b/vm.c
index 6334459579..96f4189b14 100644
--- a/vm.c
+++ b/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);
}