summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
authorKJ Tsanaktsidis <kj@kjtsanaktsidis.id.au>2023-11-12 13:24:55 +1100
committerKJ Tsanaktsidis <kj@kjtsanaktsidis.id.au>2024-01-19 09:55:12 +1100
commit807714447ef02c77bb0e17fe27d96ee2692264f8 (patch)
tree89ec73d9c7b67138d73e92b7b04150934e42af12 /vm.c
parent08edad31a6d5c9efd86bede1e942a32cff498427 (diff)
Pass down "stack start" variables from closer to the top of the stack
This commit changes how stack extents are calculated for both the main thread and other threads. Ruby uses the address of a local variable as part of the calculation for 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 too low (too close to the leaf function call) in both the main thread case and the new thread case. In the main thread case, we have the `INIT_STACK` macro, which is used for pthreads to set the `native_main_thread->stack_start` value. This value is correctly captured at the very top level of the program (in main.c). However, this is _not_ what's used to set the execution context machine stack (`th->ec->machine_stack.stack_start`); that gets set as part of a call to `ruby_thread_init_stack` in `Init_BareVM`, using the address of a local variable allocated _inside_ `Init_BareVM`. This is too low; we need to use a local allocated closer to the top of the program. In the new thread case, the lolcal is allocated inside `native_thread_init_stack`, which is, again, too low. In both cases, this means that we might have VALUEs lying outside the bounds of `th->ec->machine.stack_{start,end}`, which won't be marked correctly by the GC machinery. To fix this, * In the main thread case: We already have `INIT_STACK` at the right level, so just pass that local var to `ruby_thread_init_stack`. * In the new thread case: Allocate the local one level above the call to `native_thread_init_stack` in `call_thread_start_func2`. [Bug #20001] fix
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/vm.c b/vm.c
index a2a17f8fe7..98e280bf28 100644
--- a/vm.c
+++ b/vm.c
@@ -54,6 +54,8 @@
int ruby_assert_critical_section_entered = 0;
#endif
+static void *native_main_thread_stack_top;
+
VALUE rb_str_concat_literals(size_t, const VALUE*);
VALUE vm_exec(rb_execution_context_t *);
@@ -4206,7 +4208,8 @@ Init_BareVM(void)
th_init(th, 0, vm);
rb_ractor_set_current_ec(th->ractor, th->ec);
- ruby_thread_init_stack(th);
+ /* n.b. native_main_thread_stack_top is set by the INIT_STACK macro */
+ ruby_thread_init_stack(th, native_main_thread_stack_top);
// setup ractor system
rb_native_mutex_initialize(&vm->ractor.sync.lock);
@@ -4217,6 +4220,12 @@ Init_BareVM(void)
#endif
}
+void
+ruby_init_stack(void *addr)
+{
+ native_main_thread_stack_top = addr;
+}
+
#ifndef _WIN32
#include <unistd.h>
#include <sys/mman.h>