[ruby-core:102783] [Ruby master Bug#17677] Ractor crashes fork when blocking
From:
hsbt@...
Date:
2021-03-09 00:42:02 UTC
List:
ruby-core #102783
Issue #17677 has been updated by hsbt (Hiroshi SHIBATA).
Assignee set to ko1 (Koichi Sasada)
Status changed from Open to Assigned
----------------------------------------
Bug #17677: Ractor crashes fork when blocking
https://bugs.ruby-lang.org/issues/17677#change-90800
* Author: delner (David Elner)
* Status: Assigned
* Priority: Normal
* Assignee: ko1 (Koichi Sasada)
* ruby -v: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN
----------------------------------------
## Background
If you create a Ractor which blocks (e.g. `receive`), then fork the process, the fork will segfault upon completion.
## How to reproduce
```ruby
r2 = Ractor.new do
Ractor.receive
end
sleep(1)
puts "Forking..."
fork do
sleep(1)
puts "End fork."
end
loop do
puts "Main thread."
sleep(1)
end
```
## Expectation and result
Application prints “Main thread” from main process every second, while fork prints “End fork.” then produces a segfault. Main process continues to run.
Expected fork to not raise a segfault.
```
<internal:ractor>:267: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.
Forking...
Main thread.
Main thread.
End fork.
app/sandbox.rb:80: [BUG]: Device or resource busy (EBUSY)
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]
-- Control frame information -----------------------------------------------
c:0003 p:---- s:0011 e:000010 CFUNC :fork
c:0002 p:0048 s:0007 E:001b48 EVAL app/sandbox.rb:80 [FINISH]
c:0001 p:0000 s:0003 E:002590 (none) [FINISH]
-- Ruby level backtrace information ----------------------------------------
app/sandbox.rb:80:in `<main>'
app/sandbox.rb:80:in `fork'
-- C level backtrace information -------------------------------------------
/usr/local/lib/libruby.so.3.0(rb_print_backtrace+0x11) [0x7f9848528cfb] vm_dump.c:758
/usr/local/lib/libruby.so.3.0(rb_vm_bugreport) vm_dump.c:998
/usr/local/lib/libruby.so.3.0(bug_report_end+0x0) [0x7f9848354808] error.c:763
/usr/local/lib/libruby.so.3.0(rb_bug_without_die) error.c:763
/usr/local/lib/libruby.so.3.0(die+0x0) [0x7f98482c6902] error.c:771
/usr/local/lib/libruby.so.3.0(rb_bug) error.c:773
/usr/local/lib/libruby.so.3.0(rb_bug_errno+0x3c) [0x7f9848354a1c] error.c:802
/usr/local/lib/libruby.so.3.0(rb_native_mutex_destroy+0x20) [0x7f98484ce380] thread_pthread.c:444
/usr/local/lib/libruby.so.3.0(rb_native_cond_initialize) (null):0
/usr/local/lib/libruby.so.3.0(ractor_free+0xd) [0x7f984844487d] ractor.c:229
/usr/local/lib/libruby.so.3.0(run_final+0xb) [0x7f9848371c66] gc.c:3670
/usr/local/lib/libruby.so.3.0(finalize_list) gc.c:3689
/usr/local/lib/libruby.so.3.0(rb_objspace_call_finalizer+0x33d) [0x7f984837cc5d] gc.c:3852
/usr/local/lib/libruby.so.3.0(rb_ec_cleanup+0x311) [0x7f984835f0b1] eval.c:184
/usr/local/lib/libruby.so.3.0(ruby_stop+0x9) [0x7f984835f339] eval.c:329
/usr/local/lib/libruby.so.3.0(rb_f_fork+0x1f) [0x7f98484402f8] process.c:4348
/usr/local/lib/libruby.so.3.0(rb_f_fork) process.c:4338
/usr/local/lib/libruby.so.3.0(vm_call_cfunc_with_frame+0x11b) [0x7f984850672b] vm_insnhelper.c:2898
/usr/local/lib/libruby.so.3.0(vm_call_method_each_type+0xf9) [0x7f98485192c9] vm_insnhelper.c:3388
/usr/local/lib/libruby.so.3.0(vm_call_method+0xb4) [0x7f9848519b24] vm_insnhelper.c:3506
/usr/local/lib/libruby.so.3.0(vm_sendish+0xb3) [0x7f984850a3d3] vm_insnhelper.c:4499
/usr/local/lib/libruby.so.3.0(vm_exec_core+0x140) [0x7f98485123e0] insns.def:770
/usr/local/lib/libruby.so.3.0(rb_vm_exec+0x176) [0x7f9848517b26] vm.c:2163
/usr/local/lib/libruby.so.3.0(rb_ec_exec_node+0xd9) [0x7f9848359719] eval.c:317
/usr/local/lib/libruby.so.3.0(ruby_run_node+0x55) [0x7f984835f395] eval.c:375
/usr/local/bin/ruby(main+0x5b) [0x565147e5410b] ./main.c:50
...
Main thread.
Main thread.
Main thread.
```
## Additional notes
This does not happen if a blocking operation does not occur in the Ractor. E.g.
```ruby
r2 = Ractor.new do
loop { puts "[#{Process.pid}] Ractor"; sleep(1) }
end
```
Segfault can also be prevented by invoking `close_incoming` prior to forking, although this raises another error internally.
It also does not crash on MacOS 10.15.7: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19].
## Suggested solutions
(None)
--
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>