summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/sanitizers.h26
-rw-r--r--thread_pthread.c10
-rw-r--r--thread_win32.c3
3 files changed, 33 insertions, 6 deletions
diff --git a/internal/sanitizers.h b/internal/sanitizers.h
index 7b7d166c74..6b2a131925 100644
--- a/internal/sanitizers.h
+++ b/internal/sanitizers.h
@@ -64,6 +64,8 @@
# define __asan_poison_memory_region(x, y)
# define __asan_unpoison_memory_region(x, y)
# define __asan_region_is_poisoned(x, y) 0
+# define __asan_get_current_fake_stack() NULL
+# define __asan_addr_is_in_fake_stack(fake_stack, slot, start, end) NULL
#endif
#if !__has_feature(memory_sanitizer)
@@ -183,4 +185,28 @@ asan_unpoison_object(VALUE obj, bool newobj_p)
asan_unpoison_memory_region(ptr, SIZEOF_VALUE, newobj_p);
}
+
+/*!
+ * Checks if the given pointer is on an ASAN fake stack. If so, it returns the
+ * address this variable has on the real frame; if not, it returns the origin
+ * address unmodified.
+ *
+ * n.b. - _dereferencing_ the returned address is meaningless and should not
+ * be done; even though ASAN reserves space for the variable in both the real and
+ * fake stacks, the _value_ of that variable is only in the fake stack.
+ *
+ * n.b. - this only works for addresses passed in from local variables on the same
+ * thread, because the ASAN fake stacks are threadlocal.
+ *
+ * \param[in] slot the address of some local variable
+ * \retval a pointer to something from that frame on the _real_ machine stack
+ */
+static inline void *
+asan_get_real_stack_addr(void* slot)
+{
+ VALUE *addr;
+ addr = __asan_addr_is_in_fake_stack(__asan_get_current_fake_stack(), slot, NULL, NULL);
+ return addr ? addr : slot;
+}
+
#endif /* INTERNAL_SANITIZERS_H */
diff --git a/thread_pthread.c b/thread_pthread.c
index a6a6c9d127..af50d50699 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -12,6 +12,7 @@
#ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
#include "internal/gc.h"
+#include "internal/sanitizers.h"
#include "rjit.h"
#ifdef HAVE_SYS_RESOURCE_H
@@ -1967,6 +1968,7 @@ void
ruby_init_stack(volatile void *addr)
{
native_main_thread.id = pthread_self();
+ addr = asan_get_real_stack_addr((void *)addr);
#if MAINSTACKADDR_AVAILABLE
if (native_main_thread.stack_maxsize) return;
@@ -2065,7 +2067,7 @@ native_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame)
if (get_stack(&start, &size) == 0) {
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_start = asan_get_real_stack_addr(local_in_parent_frame);
th->ec->machine.stack_maxsize = size - diff;
}
}
@@ -2192,12 +2194,10 @@ call_thread_start_func_2(rb_thread_t *th)
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;
+ VALUE *stack_start_addr = asan_get_real_stack_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 *
diff --git a/thread_win32.c b/thread_win32.c
index e92472cea9..c294542003 100644
--- a/thread_win32.c
+++ b/thread_win32.c
@@ -11,6 +11,7 @@
#ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
+#include "internal/sanitizers.h"
#include <process.h>
#define TIME_QUANTUM_USEC (10 * 1000)
@@ -596,7 +597,7 @@ COMPILER_WARNING_IGNORED(-Wmaybe-uninitialized)
static inline SIZE_T
query_memory_basic_info(PMEMORY_BASIC_INFORMATION mi, void *local_in_parent_frame)
{
- return VirtualQuery(local_in_parent_frame, mi, sizeof(*mi));
+ return VirtualQuery(asan_get_real_stack_addr(local_in_parent_frame), mi, sizeof(*mi));
}
COMPILER_WARNING_POP