Skip to content

Commit 5bcc639

Browse files
committed
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.
1 parent 45a2c95 commit 5bcc639

File tree

3 files changed

+17
-0
lines changed

3 files changed

+17
-0
lines changed

common.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14057,6 +14057,7 @@ process.$(OBJEXT): {$(VPATH)}onigmo.h
1405714057
process.$(OBJEXT): {$(VPATH)}oniguruma.h
1405814058
process.$(OBJEXT): {$(VPATH)}process.c
1405914059
process.$(OBJEXT): {$(VPATH)}ractor.h
14060+
process.$(OBJEXT): {$(VPATH)}ractor_core.h
1406014061
process.$(OBJEXT): {$(VPATH)}ruby_assert.h
1406114062
process.$(OBJEXT): {$(VPATH)}ruby_atomic.h
1406214063
process.$(OBJEXT): {$(VPATH)}rubyparser.h

process.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ int initgroups(const char *, rb_gid_t);
114114
#include "ruby/st.h"
115115
#include "ruby/thread.h"
116116
#include "ruby/util.h"
117+
#include "ractor_core.h"
117118
#include "vm_core.h"
118119
#include "vm_sync.h"
119120
#include "ruby/ractor.h"
@@ -4120,6 +4121,10 @@ rb_fork_async_signal_safe(int *status,
41204121
rb_pid_t
41214122
rb_fork_ruby(int *status)
41224123
{
4124+
if (UNLIKELY(!rb_ractor_main_p())) {
4125+
rb_raise(rb_eRactorIsolationError, "can not fork from non-main Ractors");
4126+
}
4127+
41234128
struct rb_process_status child = {.status = 0};
41244129
rb_pid_t pid;
41254130
int try_gc = 1, err = 0;

test/ruby/test_ractor.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ class TestClass
9999
RUBY
100100
end
101101

102+
def test_fork_raise_isolation_error
103+
assert_ractor(<<~'RUBY')
104+
ractor = Ractor.new do
105+
Process.fork
106+
rescue Ractor::IsolationError => e
107+
e
108+
end
109+
assert_equal Ractor::IsolationError, ractor.value.class
110+
RUBY
111+
end if Process.respond_to?(:fork)
112+
102113
def test_require_raises_and_no_ractor_belonging_issue
103114
assert_ractor(<<~'RUBY')
104115
require "tempfile"

0 commit comments

Comments
 (0)