mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Pass down "stack start" variables from closer to the top of the stack
The implementation of `native_thread_init_stack` for the various threading models can use the address of a local variable as part of the calculation of the machine stack extents: * pthreads uses it as a lower-bound on the start of the stack, because glibc (and maybe other libcs) can store its own data on the stack before calling into user code on thread creation. * win32 uses it as an argument to VirtualQuery, which gets the extent of the memory mapping which contains the variable However, the local being used for this is actually allocated _inside_ the `native_thread_init_stack` frame; that means the caller might allocate a VALUE on the stack that actually lies outside the bounds stored in machine.stack_{start,end}. A local variable from one level above the topmost frame that stores VALUEs on the stack must be drilled down into the call to `native_thread_init_stack` to be used in the calculation. This probably doesn't _really_ matter for the win32 case (they'll be in the same memory mapping so VirtualQuery should return the same thing), but definitely could matter for the pthreads case. [Bug #20001]
This commit is contained in:
parent
6a45320c25
commit
4ba8f0dc99
9 changed files with 33 additions and 22 deletions
|
@ -1964,7 +1964,7 @@ reserve_stack(volatile char *limit, size_t size)
|
|||
|
||||
#undef ruby_init_stack
|
||||
void
|
||||
ruby_init_stack(volatile VALUE *addr)
|
||||
ruby_init_stack(volatile void *addr)
|
||||
{
|
||||
native_main_thread.id = pthread_self();
|
||||
|
||||
|
@ -2049,7 +2049,7 @@ ruby_init_stack(volatile VALUE *addr)
|
|||
{int err = (expr); if (err) {rb_bug_errno(#expr, err);}}
|
||||
|
||||
static int
|
||||
native_thread_init_stack(rb_thread_t *th)
|
||||
native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame)
|
||||
{
|
||||
rb_nativethread_id_t curr = pthread_self();
|
||||
|
||||
|
@ -2064,8 +2064,8 @@ native_thread_init_stack(rb_thread_t *th)
|
|||
size_t size;
|
||||
|
||||
if (get_stack(&start, &size) == 0) {
|
||||
uintptr_t diff = (uintptr_t)start - (uintptr_t)&curr;
|
||||
th->ec->machine.stack_start = (VALUE *)&curr;
|
||||
uintptr_t diff = (uintptr_t)start - (uintptr_t)local_in_parent_frame;
|
||||
th->ec->machine.stack_start = (uintptr_t)local_in_parent_frame;
|
||||
th->ec->machine.stack_maxsize = size - diff;
|
||||
}
|
||||
}
|
||||
|
@ -2185,8 +2185,19 @@ native_thread_create_dedicated(rb_thread_t *th)
|
|||
static void
|
||||
call_thread_start_func_2(rb_thread_t *th)
|
||||
{
|
||||
native_thread_init_stack(th);
|
||||
/* Capture the address of a local in this stack frame to mark the beginning of the
|
||||
machine stack for this thread. This is required even if we can tell the real
|
||||
stack beginning from the pthread API in native_thread_init_stack, because
|
||||
glibc stores some of its own data on the stack before calling into user code
|
||||
on a new thread, and replacing that data on fiber-switch would break it (see
|
||||
bug #13887) */
|
||||
VALUE stack_start = 0;
|
||||
VALUE *stack_start_addr = &stack_start;
|
||||
native_thread_init_stack(th, stack_start_addr);
|
||||
thread_start_func_2(th, th->ec->machine.stack_start);
|
||||
|
||||
/* Ensure that stack_start really was spilled to the stack */
|
||||
RB_GC_GUARD(stack_start)
|
||||
}
|
||||
|
||||
static void *
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue