aboutsummaryrefslogtreecommitdiffstats
path: root/thread.c
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2019-06-20 11:31:22 +1200
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2019-06-20 16:44:50 +1200
commite4cafa393f8fd4aa207f20b1d122884b4de99cf1 (patch)
tree78e6a286bcb55b6dd180153b1be9508090c25090 /thread.c
parentc26c51449461e3c8ee9bb4e1800933fb3d3caf67 (diff)
downloadruby-e4cafa393f8fd4aa207f20b1d122884b4de99cf1.tar.gz
Ensure that vm_stack is cleared in `thread_cleanup_func_before_exec`.
If `vm_stack` is left dangling in a forked process, the gc attempts to scan it, but it is invalid and will cause a segfault. Therefore, we clear it before forking. In order to simplify this, `rb_ec_clear_vm_stack` was introduced.
Diffstat (limited to 'thread.c')
-rw-r--r--thread.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/thread.c b/thread.c
index 7cb8062075..f7ed40f1df 100644
--- a/thread.c
+++ b/thread.c
@@ -596,7 +596,11 @@ thread_cleanup_func_before_exec(void *th_ptr)
{
rb_thread_t *th = th_ptr;
th->status = THREAD_KILLED;
+ // The thread stack doesn't exist in the forked process:
th->ec->machine.stack_start = th->ec->machine.stack_end = NULL;
+
+ // The vm_stack is `alloca`ed on the thread stack, so it's gone too:
+ rb_ec_clear_vm_stack(th->ec);
}
static void
@@ -713,19 +717,19 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start)
rb_bug("thread_start_func_2 must not be used for main thread");
}
+ thread_debug("thread start: %p\n", (void *)th);
+ VM_ASSERT((size * sizeof(VALUE)) <= th->ec->machine.stack_maxsize);
+
vm_stack = alloca(size * sizeof(VALUE));
VM_ASSERT(vm_stack);
gvl_acquire(th->vm, th);
rb_ec_initialize_vm_stack(th->ec, vm_stack, size);
-
- ruby_thread_set_native(th);
-
th->ec->machine.stack_start = STACK_DIR_UPPER(vm_stack + size, vm_stack);
th->ec->machine.stack_maxsize -= size * sizeof(VALUE);
- thread_debug("thread start: %p\n", (void *)th);
+ ruby_thread_set_native(th);
{
thread_debug("thread start (get lock): %p\n", (void *)th);
@@ -806,7 +810,10 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start)
rb_fiber_close(th->ec->fiber_ptr);
}
+
thread_cleanup_func(th, FALSE);
+ VM_ASSERT(th->ec->vm_stack == NULL);
+
gvl_release(th->vm);
return 0;
@@ -2253,6 +2260,7 @@ rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
if (th->status == THREAD_RUNNABLE)
th->running_time_us += TIME_QUANTUM_USEC;
+ VM_ASSERT(th->ec->cfp);
EXEC_EVENT_HOOK(th->ec, RUBY_INTERNAL_EVENT_SWITCH, th->ec->cfp->self,
0, 0, 0, Qundef);