summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <[email protected]>2025-06-24 12:33:27 +0200
committerJean Boussier <[email protected]>2025-06-24 15:10:40 +0100
commit5bcc639b341291fe0584d11c6bdd1add29f40087 (patch)
tree999a2b0dc29e12fb2964a862ac48af68f0203ad5
parent45a2c95d0f7184c9cd64ddd26699af31bea8675d (diff)
Disallow forking from non-main ractor
[Bug #17516] `fork(2)` only leave the calling thread alive in the child. Because of this forking from the non-main ractor can easily leave the VM in a corrupted state. It may be possible in the future to carefully allow forking from non-main Ractor, but shot term it's preferable to add this restriction.
-rw-r--r--common.mk1
-rw-r--r--process.c5
-rw-r--r--test/ruby/test_ractor.rb11
3 files changed, 17 insertions, 0 deletions
diff --git a/common.mk b/common.mk
index e5a4d34a0a..002f5dcef7 100644
--- a/common.mk
+++ b/common.mk
@@ -14057,6 +14057,7 @@ process.$(OBJEXT): {$(VPATH)}onigmo.h
process.$(OBJEXT): {$(VPATH)}oniguruma.h
process.$(OBJEXT): {$(VPATH)}process.c
process.$(OBJEXT): {$(VPATH)}ractor.h
+process.$(OBJEXT): {$(VPATH)}ractor_core.h
process.$(OBJEXT): {$(VPATH)}ruby_assert.h
process.$(OBJEXT): {$(VPATH)}ruby_atomic.h
process.$(OBJEXT): {$(VPATH)}rubyparser.h
diff --git a/process.c b/process.c
index 2938411c43..da9ce74027 100644
--- a/process.c
+++ b/process.c
@@ -114,6 +114,7 @@ int initgroups(const char *, rb_gid_t);
#include "ruby/st.h"
#include "ruby/thread.h"
#include "ruby/util.h"
+#include "ractor_core.h"
#include "vm_core.h"
#include "vm_sync.h"
#include "ruby/ractor.h"
@@ -4120,6 +4121,10 @@ rb_fork_async_signal_safe(int *status,
rb_pid_t
rb_fork_ruby(int *status)
{
+ if (UNLIKELY(!rb_ractor_main_p())) {
+ rb_raise(rb_eRactorIsolationError, "can not fork from non-main Ractors");
+ }
+
struct rb_process_status child = {.status = 0};
rb_pid_t pid;
int try_gc = 1, err = 0;
diff --git a/test/ruby/test_ractor.rb b/test/ruby/test_ractor.rb
index 3fc891da23..97af7e7413 100644
--- a/test/ruby/test_ractor.rb
+++ b/test/ruby/test_ractor.rb
@@ -99,6 +99,17 @@ class TestRactor < Test::Unit::TestCase
RUBY
end
+ def test_fork_raise_isolation_error
+ assert_ractor(<<~'RUBY')
+ ractor = Ractor.new do
+ Process.fork
+ rescue Ractor::IsolationError => e
+ e
+ end
+ assert_equal Ractor::IsolationError, ractor.value.class
+ RUBY
+ end if Process.respond_to?(:fork)
+
def test_require_raises_and_no_ractor_belonging_issue
assert_ractor(<<~'RUBY')
require "tempfile"