Files
ruby/thread_none.h
Yusuke EndohandClaude Opus 5.5 053f8da910 Always use the no-inline rb_current_ec()
Under the M:N thread scheduler, a Ruby thread in a non-main Ractor may be
resumed on a different native thread after it blocks. The C compiler
assumes that the native thread never changes within a function, so it may
compute the address of ruby_current_ec once (`__tls_get_addr` in
libruby.so) and reuse it after the switch. The address then refers to the
TLS of the previous native thread, which leads to a SEGV or to using
another thread's ec.

    8.times.map do
      Ractor.new do
        50.times do
          ",,".split(/(,)/) { sleep 0.001 }
        end
        :ok
      end
    end.map(&:value)
    #=> [BUG] Segmentation fault at 0x0000000000000030 (with Clang 21)

arm64 and ppc64le already use the out-of-line rb_current_ec()
(RB_THREAD_CURRENT_EC_NOINLINE), which prevents the compiler from caching
the address. Use it on all platforms, and remove the macro.

[Bug #22453]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:27:26 +09:00

27 lines
1.0 KiB
C

#ifndef RUBY_THREAD_NONE_H
#define RUBY_THREAD_NONE_H
#define RB_NATIVETHREAD_LOCK_INIT (void)(0)
#define RB_NATIVETHREAD_COND_INIT (void)(0)
// no-thread impl doesn't use TLS but define this to avoid using tls key
// based implementation in vm.c
#define RB_THREAD_LOCAL_SPECIFIER
// This model brings its own scheduler stubs (thread_none.c) instead of the
// common one; thread.c keys off this.
#define RB_THREAD_SCHED_NONE 1
// The scheduler's types are shared with the threaded platforms: the code that
// reads them (vm_sync.c, ractor.c, thread.c) is compiled for every thread
// model, so it needs the real fields even here, where nothing ever runs
// concurrently and they all stay zero. thread_none.c only ever passes the
// structs around, never looks inside them.
#include "thread_sched.h"
RUBY_EXTERN struct rb_execution_context_struct *ruby_current_ec;
NOINLINE(struct rb_execution_context_struct *rb_current_ec_noinline(void)); // for assertions
struct rb_execution_context_struct *rb_current_ec(void);
#endif /* RUBY_THREAD_NONE_H */