Ensure vm_stack is cleared after fork.

This commit is contained in:
Samuel Williams 2019-06-20 13:41:18 +12:00
parent 6bf1285b20
commit dbc2b89bc0
4 changed files with 36 additions and 20 deletions

12
cont.c
View File

@ -268,13 +268,6 @@ fiber_status_set(rb_fiber_t *fib, enum fiber_status s)
fib->status = s; fib->status = s;
} }
void
rb_ec_set_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size)
{
ec->vm_stack = stack;
ec->vm_stack_size = size;
}
static inline void static inline void
ec_switch(rb_thread_t *th, rb_fiber_t *fib) ec_switch(rb_thread_t *th, rb_fiber_t *fib)
{ {
@ -705,7 +698,7 @@ cont_capture(volatile int *volatile stat)
cont->saved_vm_stack.ptr = ALLOC_N(VALUE, ec->vm_stack_size); cont->saved_vm_stack.ptr = ALLOC_N(VALUE, ec->vm_stack_size);
MEMCPY(cont->saved_vm_stack.ptr, ec->vm_stack, VALUE, ec->vm_stack_size); MEMCPY(cont->saved_vm_stack.ptr, ec->vm_stack, VALUE, ec->vm_stack_size);
#endif #endif
rb_ec_set_vm_stack(&cont->saved_ec, NULL, 0); rb_ec_clear_vm_stack(&cont->saved_ec);
cont_save_machine_stack(th, cont); cont_save_machine_stack(th, cont);
/* backup ensure_list to array for search in another context */ /* backup ensure_list to array for search in another context */
@ -1793,8 +1786,7 @@ rb_fiber_close(rb_fiber_t *fib)
} }
} }
rb_ec_set_vm_stack(ec, NULL, 0); rb_ec_clear_vm_stack(ec);
ec->cfp = NULL;
#if !FIBER_USE_NATIVE #if !FIBER_USE_NATIVE
/* should not mark machine stack any more */ /* should not mark machine stack any more */

View File

@ -596,7 +596,11 @@ thread_cleanup_func_before_exec(void *th_ptr)
{ {
rb_thread_t *th = th_ptr; rb_thread_t *th = th_ptr;
th->status = THREAD_KILLED; 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; 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 static void

36
vm.c
View File

@ -2514,7 +2514,7 @@ rb_execution_context_mark(const rb_execution_context_t *ec)
#endif #endif
/* mark VM stack */ /* mark VM stack */
if (ec->vm_stack && ec->cfp) { if (ec->vm_stack) {
VALUE *p = ec->vm_stack; VALUE *p = ec->vm_stack;
VALUE *sp = ec->cfp->sp; VALUE *sp = ec->cfp->sp;
rb_control_frame_t *cfp = ec->cfp; rb_control_frame_t *cfp = ec->cfp;
@ -2685,20 +2685,36 @@ thread_alloc(VALUE klass)
return obj; return obj;
} }
inline void
rb_ec_set_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size)
{
ec->vm_stack = stack;
ec->vm_stack_size = size;
}
void void
rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size) rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size)
{ {
rb_ec_set_vm_stack(ec, stack, size); rb_ec_set_vm_stack(ec, stack, size);
ec->cfp = (void *)(ec->vm_stack + ec->vm_stack_size); ec->cfp = (void *)(ec->vm_stack + ec->vm_stack_size);
rb_vm_push_frame(ec, rb_vm_push_frame(ec,
NULL /* dummy iseq */, NULL /* dummy iseq */,
VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_CFRAME /* dummy frame */, VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_CFRAME /* dummy frame */,
Qnil /* dummy self */, VM_BLOCK_HANDLER_NONE /* dummy block ptr */, Qnil /* dummy self */, VM_BLOCK_HANDLER_NONE /* dummy block ptr */,
0 /* dummy cref/me */, 0 /* dummy cref/me */,
0 /* dummy pc */, ec->vm_stack, 0, 0 0 /* dummy pc */, ec->vm_stack, 0, 0
); );
}
void
rb_ec_clear_vm_stack(rb_execution_context_t *ec)
{
rb_ec_set_vm_stack(ec, NULL, 0);
// Avoid dangling pointers:
ec->cfp = NULL;
} }
static void static void

View File

@ -907,6 +907,10 @@ void rb_ec_set_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size);
// @param size the size of the stack, as in `VALUE stack[size]`. // @param size the size of the stack, as in `VALUE stack[size]`.
void rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size); void rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size);
// Clear (set to `NULL`) the vm_stack pointer and frame pointer in the execution context.
// @param ec the execution context to update.
void rb_ec_clear_vm_stack(rb_execution_context_t *ec);
typedef struct rb_thread_struct { typedef struct rb_thread_struct {
struct list_node vmlt_node; struct list_node vmlt_node;
VALUE self; VALUE self;