ml.ruby-lang.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

ruby-core

Thread Start a new thread
Download
Threads by month
  • ----- 2026 -----
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
ruby-core@ml.ruby-lang.org

April 2025

  • 3 participants
  • 204 discussions
[ruby-core:121450] [Ruby Bug#21200] Ractor spuriously hangs, segfault or errors
by Eregon (Benoit Daloze) 08 Sep '26

08 Sep '26
Issue #21200 has been reported by Eregon (Benoit Daloze). ---------------------------------------- Bug #21200: Ractor spuriously hangs, segfault or errors https://bugs.ruby-lang.org/issues/21200 * Author: Eregon (Benoit Daloze) * Status: Open * Assignee: ractor * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- For a new test `test_ractor_parallel` I added in https://github.com/ruby/etc/pull/52/files This seems a Ractor bug. Example failures: https://github.com/ruby/ruby/actions/runs/14097239052/job/39486770259?pr=12… ``` 1) Failure: TestEtc#test_ractor_parallel [/Users/runner/work/ruby/ruby/src/test/etc/test_etc.rb:178]: assert_separately failed with error message pid 51588 exit 0 | [BUG] ``` https://github.com/ruby/ruby/actions/runs/14094646363/job/39479353266?pr=12… ``` TestEtc#test_ractor_parallel [/Users/runner/work/ruby/ruby/src/test/etc/test_etc.rb:178]: assert_separately failed with error message pid 47346 exit 0 | [BUG] pthread_mutex_lock: Invalid argument (EINVAL) | ruby 3.5.0dev (2025-03-26T22:25:25Z pull/12984/merge 1ea32181b7) +PRISM [arm64-darwin23] | | -- Crash Report log information -------------------------------------------- | See Crash Report log file in one of the following locations: | * ~/Library/Logs/DiagnosticReports | * /Library/Logs/DiagnosticReports | for more details. | Don't forget to include the above Crash Report log file in bug reports. | | -- Control frame information ----------------------------------------------- | | | -- Threading information --------------------------------------------------- | Total ractor count: 1 | Ruby thread count for this ractor: 0 | | -- C level backtrace information ------------------------------------------- | [BUG] Segmentation fault at 0xfffffffffffffff8 | ruby 3.5.0dev (2025-03-26T22:25:25Z pull/12984/merge 1ea32181b7) +PRISM [arm64-darwin23] | | -- Crash Report log information -------------------------------------------- | See Crash Report log file in one of the following locations: | * ~/Library/Logs/DiagnosticReports | * /Library/Logs/DiagnosticReports | for more details. | Don't forget to include the above Crash Report log file in bug reports. | | Crashed while printing bug report | [IMPORTANT] | Don't forget to include the Crash Report log file under | DiagnosticReports directory in bug reports. | ``` https://github.com/ruby/ruby/actions/runs/14069270994/job/39402894235#step:… ``` 1) Error: TestEtc#test_ractor_parallel: Test::Unit::ProxyError: execution of Test::Unit::CoreAssertions#assert_separately expired timeout (10 sec) pid 145797 killed by SIGKILL (signal 9) | /home/runner/work/ruby/ruby/src/test/etc/test_etc.rb:178:in 'TestEtc#test_ractor_parallel' ``` The test has been disabled for now in https://github.com/ruby/ruby/pull/12992. -- https://bugs.ruby-lang.org/
2 1
0 0
[ruby-core:111960] [Ruby master Bug#19364] Issue with tracepoint enable/disable across ractors
by luke-gru (Luke Gruber) 08 Sep '26

08 Sep '26
Issue #19364 has been reported by luke-gru (Luke Gruber). ---------------------------------------- Bug #19364: Issue with tracepoint enable/disable across ractors https://bugs.ruby-lang.org/issues/19364 * Author: luke-gru (Luke Gruber) * Status: Open * Priority: Normal * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- This sometimes segfaults: ```ruby def test_enable_disable_in_multiple_ractors_with_target rs = [] 100.times do |i| # setup new iseqs Kernel.define_method :"my_method_to_change_for_tracing_#{i}" do true end end 100.times do |i| rs << Ractor.new(i) do |j| meth = :"my_method_to_change_for_tracing_#{j}" tp = TracePoint.new(:line) { } # local to ractor 100.times do tp.enable(target: method(meth)) # change iseq internals of given method, should be done with lock tp.disable # disable hooks should hold lock too, changes method definition internals end end end rs.each(&:take) # shouldn't raise end test_enable_disable_in_multiple_ractors_with_target() ``` Changing iseq internals is done without the VM lock. This is true in Tracepoint#enable and Tracepoint#disable methods. I have a patch coming. -- https://bugs.ruby-lang.org/
3 2
0 0
[ruby-core:116061] [Ruby master Bug#20158] Ractor affects Coverage results
by janosch-x 08 Sep '26

08 Sep '26
Issue #20158 has been reported by janosch-x (Janosch Müller). ---------------------------------------- Bug #20158: Ractor affects Coverage results https://bugs.ruby-lang.org/issues/20158 * Author: janosch-x (Janosch Müller) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0preview1 (2023-05-12 master a1b01e7701) [arm64-darwin22] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I have a large rspec test suite. I found that if I call a Ractor, the Coverage results are strongly affected, i.e. almost all files appear to be uncovered. This happens even if I only ever call a Ractor before the library or rspec are required. Unfortunately, I was not able to build a simple repro yet. I assume it is a timing thing and only affects larger suites, or it only happens if there are multiple files, and maybe if the library lazily requires its sub-modules? However, I guess this should produce the same results when added to the spec_helper.rb of other large suites: ```ruby # Ractor.new { nil } # uncomment this to affect coverage results require 'coverage' Coverage.start # require library, set up rspec etc. RSpec.configuration.after(:suite) do # this number is greatly reduced and unstable when calling Ractor above p Coverage.result.values.sum { |arr| arr.sum(&:to_i) } end ``` I had this problem in [this library](https://github.com/jaynetics/character_set/). The problem affects simplecov users as well, as described [here](https://github.com/simplecov-ruby/simplecov/issues/1058). -- https://bugs.ruby-lang.org/
4 5
0 0
[ruby-core:112091] [Ruby master Bug#19387] Issue with ObjectSpace.each_objects not returning IO objects after starting a ractor
by luke-gru (Luke Gruber) 08 Sep '26

08 Sep '26
Issue #19387 has been reported by luke-gru (Luke Gruber). ---------------------------------------- Bug #19387: Issue with ObjectSpace.each_objects not returning IO objects after starting a ractor https://bugs.ruby-lang.org/issues/19387 * Author: luke-gru (Luke Gruber) * Status: Open * Priority: Normal * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- ```ruby r = Ractor.new do receive # block, the problem is not the termination of the ractor but the starting end ObjectSpace.each_object(IO) { |io| p io # we get no objects } ``` -- https://bugs.ruby-lang.org/
6 9
0 0
[ruby-core:115328] [Ruby master Bug#19996] `RUBY_MN_THREADS=1` triggers Action Cable unit test failures
by yahonda (Yasuo Honda) 08 Sep '26

08 Sep '26
Issue #19996 has been reported by yahonda (Yasuo Honda). ---------------------------------------- Bug #19996: `RUBY_MN_THREADS=1` triggers Action Cable unit test failures https://bugs.ruby-lang.org/issues/19996 * Author: yahonda (Yasuo Honda) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-11-09T16:24:15Z :detached: c49adfab5d) +MN [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- ### Steps to reproduce 1. Install `ruby 3.3.0dev` 2. Set `RUBY_MN_THREADS=1` environment variable 3. git clone https://github.com/rails/rails cd rails rm Gemfile.lock bundle install cd actioncable bin/test test/channel/base_test.rb test/subscription_adapter/redis_test.rb test/channel/test_case_test.rb test/subscription_adapter/redis_test.rb test/client_test.rb --seed 14800 ``` ### Expected behavior It should pass as not setting ``` $ unset RUBY_MN_THREADS $ bin/test test/channel/base_test.rb test/subscription_adapter/redis_test.rb test/channel/test_case_test.rb test/subscription_adapter/redis_test.rb test/client_test.rb --seed 14800 /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/minitest-5.20.0/lib/minitest.rb:3: warning: mutex_m which will no longer be part of the default gems since Ruby 3.4.0. Add mutex_m to your Gemfile or gemspec. Run options: --seed 14800 # Running: ......................................................................... Finished in 12.031310s, 6.0675 runs/s, 46.7115 assertions/s. 73 runs, 562 assertions, 0 failures, 0 errors, 0 skips $ ``` ### Actual behavior It usually fails as follows. ``` $ bin/test test/channel/base_test.rb test/subscription_adapter/redis_test.rb test/channel/test_case_test.rb test/subscription_adapter/redis_test.rb test/client_test.rb --seed 14800 /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/minitest-5.20.0/lib/minitest.rb:3: warning: mutex_m which will no longer be part of the default gems since Ruby 3.4.0. Add mutex_m to your Gemfile or gemspec. Run options: --seed 14800 # Running: ..................................................F Failure: RedisAdapterTest::AlternateConfiguration#test_channel_prefix [/home/yahonda/src/github.com/rails/rails/actioncable/test/subscription_adapter/common.rb:35]: Expected #<Concurrent::Event:0x00007f0b2698d4f0 @__Lock__=#<Thread::Mutex:0x00007f0b26f8cab8>, @__Condition__=#<Thread::ConditionVariable:0x00007f0b26f8ca90>, @set=false, @iteration=0> to be set?. bin/test test/subscription_adapter/channel_prefix.rb:6 .F Failure: RedisAdapterTest::AlternateConfiguration#test_multiple_broadcast [/home/yahonda/src/github.com/rails/rails/actioncable/test/subscription_adapter/common.rb:35]: Expected #<Concurrent::Event:0x00007f0b2698a4d0 @__Lock__=#<Thread::Mutex:0x00007f0b26fac688>, @__Condition__=#<Thread::ConditionVariable:0x00007f0b26fac4f8>, @set=false, @iteration=0> to be set?. bin/test test/subscription_adapter/common.rb:74 E Error: ClientTest#test_interacting_clients: ThreadError: queue empty <internal:thread_sync>:18:in `pop' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:168:in `read_message' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:241:in `block (2 levels) in test_interacting_clients' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:218:in `block (2 levels) in concurrently' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/promises.rb:1583:in `evaluate_to' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/promises.rb:1766:in `block in on_resolvable' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:352:in `run_task' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:343:in `block (3 levels) in create_worker' <internal:kernel>:187:in `loop' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:334:in `block (2 levels) in create_worker' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:333:in `catch' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:333:in `block in create_worker' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/promises.rb:1258:in `raise' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/promises.rb:1258:in `wait_until_resolved!' /home/yahonda/.rbenv/versions/trunk/lib/ruby/gems/3.3.0+0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/promises.rb:988:in `value!' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:218:in `map' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:218:in `concurrently' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:240:in `block in test_interacting_clients' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:90:in `with_puma_server' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:234:in `test_interacting_clients' bin/test test/client_test.rb:233 E Error: ClientTest#test_disappearing_client: ThreadError: queue empty <internal:thread_sync>:18:in `pop' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:168:in `read_message' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:275:in `block in test_disappearing_client' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:90:in `with_puma_server' /home/yahonda/src/github.com/rails/rails/actioncable/test/client_test.rb:273:in `test_disappearing_client' bin/test test/client_test.rb:272 .................. Finished in 1323.812615s, 0.0551 runs/s, 0.3830 assertions/s. 73 runs, 507 assertions, 2 failures, 2 errors, 0 skips $ ``` -- https://bugs.ruby-lang.org/
3 2
0 0
[ruby-core:118182] [Ruby master Bug#20526] File.open(encoding: "bom|utf-8") converts "\r\n" to "\n" on Windows
by kou (Kouhei Sutou) 08 Sep '26

08 Sep '26
Issue #20526 has been reported by kou (Kouhei Sutou). ---------------------------------------- Bug #20526: File.open(encoding: "bom|utf-8") converts "\r\n" to "\n" on Windows https://bugs.ruby-lang.org/issues/20526 * Author: kou (Kouhei Sutou) * Status: Open * Target version: 3.2 * ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x64-mingw-ucrt] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I'm not sure whether this is an intentional behavior but it seems that `encoding: "utf-8"` doesn't change newline conversion but `encoding: "bom|utf-8"` changes newline conversion: ```ruby File.write("a.txt", "a\r\n") File.read("a.txt").bytes # => [97, 13, 10] File.open("a.txt", encoding: "utf-8") {|f| f.read.bytes} # => [97, 10, 10] File.open("a.txt", encoding: "bom|utf-8") {|f| f.read.bytes} # => [97, 10] XXX: \r\n -> \n File.open("a.txt", encoding: "bom|utf-8", universal_newline: false) {|f| f.read.bytes} # => [97, 13, 10] ``` Note that the `XXX: ` line the above codes. Is this an intentional behavior? -- https://bugs.ruby-lang.org/
3 5
0 0
[ruby-core:120897] [Ruby master Bug#21119] Programs containing `Dir.glob` with a thread executing a CPU-heavy task run very slowly.
by genya0407 (Yusuke Sangenya) 04 Sep '26

04 Sep '26
Issue #21119 has been reported by genya0407 (Yusuke Sangenya). ---------------------------------------- Bug #21119: Programs containing `Dir.glob` with a thread executing a CPU-heavy task run very slowly. https://bugs.ruby-lang.org/issues/21119 * Author: genya0407 (Yusuke Sangenya) * Status: Open * ruby -v: ruby 3.5.0dev (2025-02-06T14:10:34Z master adbf9c5b36) +PRISM [arm64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Executing the following code in Ruby 3.4.1 takes a very long time, especially when there are many files \(100~\) in the current directory. This delay does not occur in Ruby 3.3.6. ## Reproducible script ```ruby # hoge.rb # Launch a thread to execute CPU-heavy task Thread.new do loop do arr = [] 100.times do arr << rand(1...100) end end end # Execute a program containing `Dir.glob` in the main thread. 10.times do Dir.glob('*') puts "aaaa" end ``` ## Execution Results Executiong the above code in Ruby 3.4.1 takes **119.43s**. ```shell $ ruby -v ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24] $ time ruby hoge.rb aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa ruby hoge.rb 119.43s user 0.30s system 99% cpu 1:59.89 total ``` Executing it in Ruby master also takes **118.87s**. ```shell $ ~/opt-ruby/bin/ruby -v ruby 3.5.0dev (2025-02-06T14:10:34Z master adbf9c5b36) +PRISM [arm64-darwin24] $ time ~/opt-ruby/bin/ruby hoge.rb aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa ~/opt-ruby/bin/ruby hoge.rb 118.87s user 0.46s system 99% cpu 2:00.45 total ``` Executing it in Ruby 3.3.6 takes only **2.22s**. ```shell $ ruby -v ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [arm64-darwin24] $ time ruby hoge.rb aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa ruby hoge.rb 2.22s user 0.03s system 98% cpu 2.286 total ``` So, there are roughly **50x** delays. ## Possible Cause From Ruby 3.4.0, `Dir.glob` releases the GVL frequently. * https://bugs.ruby-lang.org/issues/20587 * https://github.com/ruby/ruby/pull/11147 Due to this change, when a CPU-heavy thread releases the GVL, `Dir.glob` also releases the GVL immediately. As a result, `Dir.glob` gets significantly delayed because it has to continuously regain the GVL causing a major slowdown in execution. ## Note about Execution Results I measured the execution results under a stress condition, with 100 files in the current directory. If there are fewer files, the slowdown may be less pronounced. -- https://bugs.ruby-lang.org/
6 6
0 0
[ruby-core:116615] [Ruby master Bug#20243] M:N threading VM_ASSERT failure in rb_current_execution_context with clang 17 (on Linux)
by kjtsanaktsidis (KJ Tsanaktsidis) 30 Aug '26

30 Aug '26
Issue #20243 has been reported by kjtsanaktsidis (KJ Tsanaktsidis). ---------------------------------------- Bug #20243: M:N threading VM_ASSERT failure in rb_current_execution_context with clang 17 (on Linux) https://bugs.ruby-lang.org/issues/20243 * Author: kjtsanaktsidis (KJ Tsanaktsidis) * Status: Open * Priority: Normal * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- When building with Clang 17 and `-DVM_CHECK_MODE=1` (with the following configure) ``` optflags="-ggdb3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -O3" cflags="-DVM_CHECK_MODE=1" CC=clang ../configure --prefix=/home/kj/ruby/installed --enable-yjit=dev --disable-install-doc ``` And then running the following script with the built `./miniruby` (which is actually from `bootstraptest/test_ractor.rb`): ```ruby counts = [] counts << Ractor.count ractors = (1..3).map { Ractor.new { Ractor.receive } } counts << Ractor.count ractors[0].send('End 0').take sleep 0.1 until ractors[0].inspect =~ /terminated/ counts << Ractor.count ractors[1].send('End 1').take sleep 0.1 until ractors[1].inspect =~ /terminated/ counts << Ractor.count ractors[2].send('End 2').take sleep 0.1 until ractors[2].inspect =~ /terminated/ counts << Ractor.count counts.inspect ``` I get the following crash: ``` Assertion Failed: ../vm_core.h:1957:rb_current_execution_context:ec == rb_current_ec_noinline() ruby 3.4.0dev (2024-02-07T07:52:06Z ktsanaktsidis/igno.. 5cc6d944c2) [x86_64-linux] -- Control frame information ----------------------------------------------- c:0003 p:0003 s:0010 e:000009 METHOD <internal:ractor>:431 c:0002 p:0004 s:0006 e:000005 BLOCK ractor_crash.rb:3 [FINISH] c:0001 p:---- s:0003 e:000002 DUMMY [FINISH] -- Ruby level backtrace information ---------------------------------------- ractor_crash.rb:3:in `block (2 levels) in <main>' <internal:ractor>:431:in `receive' -- Threading information --------------------------------------------------- Total ractor count: 2 Ruby thread count for this ractor: 1 -- C level backtrace information ------------------------------------------- /home/kj/ruby/build/miniruby(rb_print_backtrace+0x14) [0x55faa97a4ebd] ../vm_dump.c:820 /home/kj/ruby/build/miniruby(rb_vm_bugreport) ../vm_dump.c:1151 /home/kj/ruby/build/miniruby(rb_assert_failure+0x81) [0x55faa94d2719] ../error.c:1131 ./miniruby(thread_sched_wait_running_turn+0x2e9) [0x55faa9726f59] /home/kj/ruby/build/miniruby(rb_ractor_sched_sleep+0x10b) [0x55faa972687b] ../thread_pthread.c:1348 /home/kj/ruby/build/miniruby(ractor_check_ints+0x0) [0x55faa968b328] ../ractor.c:683 /home/kj/ruby/build/miniruby(ractor_sleep_with_cleanup) ../ractor.c:684 /home/kj/ruby/build/miniruby(ractor_sleep+0x15) [0x55faa968adf4] ../ractor.c:701 /home/kj/ruby/build/miniruby(ractor_wait_receive) ../ractor.c:748 /home/kj/ruby/build/miniruby(ractor_receive+0x1f) [0x55faa968768e] ../ractor.c:762 /home/kj/ruby/build/miniruby(builtin_inline_class_431) ../ractor.rb:432 /home/kj/ruby/build/miniruby(builtin_invoker0+0x6) [0x55faa978fc66] ../vm_insnhelper.c:6746 /home/kj/ruby/build/miniruby(invoke_bf+0x39) [0x55faa979816e] ../vm_insnhelper.c:6886 /home/kj/ruby/build/miniruby(vm_invoke_builtin_delegate) ../vm_insnhelper.c:6909 /home/kj/ruby/build/miniruby(rb_vm_check_ints+0x0) [0x55faa9771fac] ../insns.def:1533 /home/kj/ruby/build/miniruby(vm_pop_frame) ../vm_insnhelper.c:419 /home/kj/ruby/build/miniruby(vm_exec_core) ../insns.def:1537 /home/kj/ruby/build/miniruby(vm_exec_loop+0x0) [0x55faa9767f02] ../vm.c:2489 /home/kj/ruby/build/miniruby(rb_vm_exec) ../vm.c:2492 /home/kj/ruby/build/miniruby(invoke_block+0x6f) [0x55faa9781a58] ../vm.c:1512 /home/kj/ruby/build/miniruby(invoke_iseq_block_from_c) ../vm.c:1582 /home/kj/ruby/build/miniruby(invoke_block_from_c_proc) ../vm.c:1680 /home/kj/ruby/build/miniruby(vm_invoke_proc) ../vm.c:1710 /home/kj/ruby/build/miniruby(rb_vm_invoke_proc_with_self+0x5a) [0x55faa9781eaa] ../vm.c:1745 /home/kj/ruby/build/miniruby(thread_do_start_proc+0x199) [0x55faa9739e19] ../thread.c:574 /home/kj/ruby/build/miniruby(thread_do_start+0x6c) [0x55faa973933f] ../thread.c:618 /home/kj/ruby/build/miniruby(thread_start_func_2) ../thread.c:668 /home/kj/ruby/build/miniruby(rb_native_mutex_lock+0x0) [0x55faa973a141] ../thread_pthread.c:2234 /home/kj/ruby/build/miniruby(thread_sched_lock_) ../thread_pthread.c:387 /home/kj/ruby/build/miniruby(call_thread_start_func_2) ../thread_pthread_mn.c:436 /home/kj/ruby/build/miniruby(co_start) ../thread_pthread_mn.c:434 ``` The failing assertion is this one in vm_core.h: https://github.com/ruby/ruby/blob/42c36269403baac67b0d5dc1d6d6e31168cf6a1f/…. It actually has a very helpful comment. ``` /* On the shared objects, `__tls_get_addr()` is used to access the TLS * and the address of the `ruby_current_ec` can be stored on a function * frame. However, this address can be mis-used after native thread * migration of a coroutine. * 1) Get `ptr =&ruby_current_ec` op NT1 and store it on the frame. * 2) Context switch and resume it on the NT2. * 3) `ptr` is used on NT2 but it accesses to the TLS on NT1. * This assertion checks such misusage. * * To avoid accidents, `GET_EC()` should be called once on the frame. * Note that inlining can produce the problem. */ VM_ASSERT(ec == rb_current_ec_noinline()); ``` What seems to be happening is exactly that. This is a disassembly of the relevant bits of `thread_sched_wait_running_turn`: ``` ........ # This is the only bits of the entire function which access the TLS base register %fs. # It seems to have spilled the value of ruby_current_ec into %r13. 0x000055603d2e1cf8 <+136>: mov $0xffffffffffffff90,%rax 0x000055603d2e1cff <+143>: mov %fs:0x0,%r12 0x000055603d2e1d08 <+152>: add %rax,%r12 0x000055603d2e1d0b <+155>: mov %fs:(%rax),%r13 ........ # There's a call to coroutine_transfer, so after this point we're returned to on a # different thread 0x000055603d2e1e90 <+544>: call 0x55603d7fce84 <coroutine_transfer> # But nothing ever loads the address of ruby_current_ec from %fs again (i didn't trace # exactly the data flow from %r13 at 0x000055603d2e1d0b to here, but i assume it spilled # somewhere and now got loaded back into %r15 here). In any case, that means %r15 here # contains the value of ruby_current_ec from the _old_ thread, not the current one. 0x000055603d2e1e95 <+549>: mov %rbx,0x28(%r14) 0x000055603d2e1e99 <+553>: mov (%r12),%r15 0x000055603d2e1e9d <+557>: call 0x55603d33a010 <rb_current_ec_noinline> 0x000055603d2e1ea2 <+562>: cmp %rax,%r15 => 0x000055603d2e1ea5 <+565>: jne 0x55603d2e1f3a <thread_sched_wait_running_turn+714> ........ # assertion failure code path. 0x000055603d2e1f3a <+714>: lea 0x542c0c(%rip),%rdi # 0x55603d824b4d 0x000055603d2e1f41 <+721>: lea 0x542c12(%rip),%rdx # 0x55603d824b5a 0x000055603d2e1f48 <+728>: lea 0x542c28(%rip),%rcx # 0x55603d824b77 0x000055603d2e1f4f <+735>: mov $0x7a5,%esi 0x000055603d2e1f54 <+740>: call 0x55603d08d698 <rb_assert_failure> ``` if we look at the register values from `0x000055603d2e1ea2`: ``` (rr) print/x $rax $2 = 0x55603e159ad0 (rr) print/x $r15 $3 = 0x0 ``` So the value from `%rax` which came from `ruby_current_ec_noinline` is correctly the value of `ruby_current_ec` for this thread, and `%r15` contains a stale value from a previous thread. - Now, what can we _do_ about this, is a different question :/ There's a really good stackoverflow answer about it here: https://stackoverflow.com/questions/75592038/how-to-disable-clang-expressio…, but to summarise * longstanding GCC and Clang bugs for this exist and have been marked as WONTFIX (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=26461, https://github.com/llvm/llvm-project/issues/19551) * It's even worse than this EC problem - things like `errno` also might be incorrectly persisted across coroutine switches (so e.g. an inlined C library function could in theory set `errno` in another thread, for example) * C++ actually has coroutines now, so this _must_ work for those. Clang at least has fixed some TLS problems in their C++ coroutine implementation (https://github.com/llvm/llvm-project/issues/47179) Other than reimplementing all of our coroutine stuff on top of C++ coroutines, I'm not sure what else we can do. AFAICT there's no way to tell the compiler that we clobbered the `%fs` register because that's just not a thing in its model (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66631, but i assume clang is similar). Thoughts? For now I think my workaround is to disable M:N at build time when building with ASAN (or turn optimizations down). At least this isn't a problem with `Fiber` because we never move them across threads (probably for this reason in part). -- https://bugs.ruby-lang.org/
3 4
0 0
[ruby-core:120034] [Ruby master Bug#20917] redo/next in nested begin block causes wrong order of execution
by hoshiumiarata (Arata Hoshiumi) 30 Aug '26

30 Aug '26
Issue #20917 has been reported by hoshiumiarata (Arata Hoshiumi). ---------------------------------------- Bug #20917: redo/next in nested begin block causes wrong order of execution https://bugs.ruby-lang.org/issues/20917 * Author: hoshiumiarata (Arata Hoshiumi) * Status: Open * ruby -v: ruby 3.3.5 (2024-09-03 revision ef084cc8f4) [x86_64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- It seems that `redo`/`next` in a nested `begin` block can cause the wrong order of execution. For example: ```ruby for _ in [0] puts 0 begin puts 1 begin puts 2 redo ensure puts 3 end ensure puts 4 break end end ``` It prints: ``` 0 1 2 3 4 3 4 => nil ``` But I think it should print: ``` 0 1 2 3 4 => nil ``` Because execution order should be: 1. `puts 0` 2. `puts 1` 3. `puts 2` 4. `redo` 5. unwind to nested `ensure` block 6. `puts 3` 7. unwind to outer `ensure` block 8. `puts 4` 9. `break` 10. end of loop Interestingly enough, if we add an empty `rescue` block before any of the `ensure` blocks, then the execution order is correct. -- https://bugs.ruby-lang.org/
4 3
0 0
[ruby-core:114645] [Ruby master Bug#19865] Segfault when calling user signal handlers during VM shutdown
by ivoanjo (Ivo Anjo) 27 Aug '26

27 Aug '26
Issue #19865 has been reported by ivoanjo (Ivo Anjo). ---------------------------------------- Bug #19865: Segfault when calling user signal handlers during VM shutdown https://bugs.ruby-lang.org/issues/19865 * Author: ivoanjo (Ivo Anjo) * Status: Open * Priority: Normal * ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Howdy 👋! I work for Datadog [on the `ddtrace` gem](https://github.com/DataDog/dd-trace-rb) . I've found this issue while investigating a [customer crash report](https://github.com/DataDog/dd-trace-rb/issues/2980). ### Background The original issue was found in a production app. A number of things need to be in play to cause it. The [`ruby-odbc`](https://rubygems.org/gems/ruby-odbc) gem provides a way of accessing databases through the ODBC API. It wraps a database connection as a Data object, with a free function that, prior to freeing the native resources, disconnects from the database if the connection was still active. Because disconnecting from the database is a blocking operation, the gem (reasonably, in my opinion), releases the global VM lock before disconnecting. The trigger for the crash is: 1. The app in question used puma, and puma installs a `Signal.trap('TERM')` 2. The database object was still connected when the app started to shut down 3. A VM shutdown starts... 4. Half-way through shutdown, the VM received a SIGTERM signal, and queued it for processing 5. The VM calls the free function on all objects 6. The ruby-odbc gem sees there's an active database connection, and tries to release the GVL to call the blocking disconnect 7. Before releasing the GVL, the VM checks for pending interruptions 8. The VM tries to run the Ruby-level signal handler method half-way through VM shutdown, when you can no longer run Ruby code 9. Segfault ### How to reproduce (Ruby version & script) I was able to reproduce on a minimal example on Ruby 3.2.2 (`ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]`) and recent master (`ruby 3.3.0dev (2023-08-17T07:30:01Z master d26b015e83) [x86_64-linux]`). I've put the test-case up on github as well <https://github.com/DataDog/signal-bug-testcase>, but here's the important bits: `signal-bug-testcase.rb`: ```ruby require 'signal_bug_testcase' Signal.trap("TERM") { puts "Hello, world" } FOO = SignalBugTestcase.new ``` `signal_bug_testcase.c`: ```ruby #include <ruby.h> #include <ruby/thread.h> #include <signal.h> #include <unistd.h> typedef struct { int dummy; } BugTestcase; void *test_nogvl(void *unused) { fprintf(stderr, "GVL released!\n"); return NULL; } static void bug_testcase_free(void* ptr) { fprintf(stderr, "Free getting called! Sending signal...\n"); kill(getpid(), SIGTERM); fprintf(stderr, "SIGTERM signal queued, trying to release GVL...\n"); rb_thread_call_without_gvl(test_nogvl, NULL, NULL, NULL); fprintf(stderr, "After releasing GVL!\n"); free(ptr); } const rb_data_type_t bug_testcase_data_type = { .wrap_struct_name = "SignalBugTestcase", .function = { NULL, bug_testcase_free, NULL }, .flags = RUBY_TYPED_FREE_IMMEDIATELY }; VALUE bug_testcase_alloc(VALUE klass) { BugTestcase* obj = calloc(1, sizeof(BugTestcase)); return TypedData_Make_Struct(klass, BugTestcase, &bug_testcase_data_type, obj); } void Init_signal_bug_testcase(void) { VALUE cBugTestcase = rb_define_class("SignalBugTestcase", rb_cObject); rb_define_alloc_func(cBugTestcase, bug_testcase_alloc); } ``` ### Expectation and result No segfault happens. Interestingly, on Ruby 2.7, the VM exits half-way through but doesn't always segfault, but running it a few times always triggers the issue. On 3.2+ it crashes every time for me. I suspect the right thing here is to no longer accept/try to run any Ruby-level signal handlers after VM shutdown starts. Here's what I see with this test-case: ``` $ bundle exec ruby lib/signal-bug-testcase.rb Free getting called! Sending signal... SIGTERM signal queued, trying to release GVL... lib/signal-bug-testcase.rb:3: [BUG] Segmentation fault at 0x0000000000000007 ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux] -- Control frame information ----------------------------------------------- c:0003 p:---- s:0011 e:000010 CFUNC :puts c:0002 p:0005 s:0006 e:000005 BLOCK lib/signal-bug-testcase.rb:3 [FINISH] c:0001 p:0000 s:0003 E:0001a0 DUMMY [FINISH] -- Ruby level backtrace information ---------------------------------------- lib/signal-bug-testcase.rb:3:in `block in <main>' lib/signal-bug-testcase.rb:3:in `puts' -- Machine register context ------------------------------------------------ RIP: 0x000070aa64cedbe7 RBP: 0x000070aa648e8fd0 RSP: 0x00007ffc5c057608 RAX: 0x0000000000004171 RBX: 0x00007ffc5c057630 RCX: 0x0000000000000001 RDX: 0x00007ffc5c057630 RDI: 0x0000000000000007 RSI: 0x0000000000004171 R8: 0x000000000000021b R9: 0x0000000000000000 R10: 0x000070aa63eff048 R11: 0x0000000000000000 R12: 0x000070aa648e8fd0 R13: 0x0000000000004171 R14: 0x0000000000000007 R15: 0x000070aa648e8ff0 EFL: 0x0000000000010202 -- C level backtrace information ------------------------------------------- ruby-3.2.2/lib/libruby.so.3.2(rb_print_backtrace+0xd) [0x70aa64d5bb5f] ruby-3.2.2/vm_dump.c:785 ruby-3.2.2/lib/libruby.so.3.2(rb_vm_bugreport) ruby-3.2.2/vm_dump.c:1080 ruby-3.2.2/lib/libruby.so.3.2(rb_bug_for_fatal_signal+0xf4) [0x70aa64b52164] ruby-3.2.2/error.c:813 ruby-3.2.2/lib/libruby.so.3.2(sigsegv+0x4d) [0x70aa64cab0fd] ruby-3.2.2/signal.c:964 /lib/x86_64-linux-gnu/libc.so.6(0x70aa64642520) [0x70aa64642520] ruby-3.2.2/lib/libruby.so.3.2(hash_table_index+0x0) [0x70aa64cedbe7] ruby-3.2.2/symbol.h:72 ruby-3.2.2/lib/libruby.so.3.2(rb_id_table_lookup) ruby-3.2.2/id_table.c:230 ruby-3.2.2/lib/libruby.so.3.2(cached_callable_method_entry+0x24) [0x70aa64d356bb] ruby-3.2.2/vm_method.c:1295 ruby-3.2.2/lib/libruby.so.3.2(callable_method_entry_or_negative) ruby-3.2.2/vm_method.c:1365 ruby-3.2.2/lib/libruby.so.3.2(callable_method_entry) ruby-3.2.2/vm_method.c:1402 ruby-3.2.2/lib/libruby.so.3.2(rb_callable_method_entry) ruby-3.2.2/vm_method.c:1409 ruby-3.2.2/lib/libruby.so.3.2(gccct_method_search_slowpath+0x38) [0x70aa64d36258] ruby-3.2.2/vm_eval.c:434 ruby-3.2.2/lib/libruby.so.3.2(rb_call0+0x267) [0x70aa64d4e877] ruby-3.2.2/vm_eval.c:483 ruby-3.2.2/lib/libruby.so.3.2(rb_call+0x32) [0x70aa64d4f406] ruby-3.2.2/vm_eval.c:877 ruby-3.2.2/lib/libruby.so.3.2(rb_funcallv_kw) ruby-3.2.2/vm_eval.c:1074 ruby-3.2.2/lib/libruby.so.3.2(vm_call_cfunc_with_frame+0x127) [0x70aa64d30277] ruby-3.2.2/vm_insnhelper.c:3268 ruby-3.2.2/lib/libruby.so.3.2(vm_sendish+0x97) [0x70aa64d407a4] ruby-3.2.2/vm_insnhelper.c:5080 ruby-3.2.2/lib/libruby.so.3.2(vm_exec_core) ruby-3.2.2/insns.def:820 ruby-3.2.2/lib/libruby.so.3.2(rb_vm_exec+0xd3) [0x70aa64d460d3] ruby-3.2.2/vm.c:2374 ruby-3.2.2/lib/libruby.so.3.2(rb_vm_invoke_proc+0x5f) [0x70aa64d4bfcf] ruby-3.2.2/vm.c:1603 ruby-3.2.2/lib/libruby.so.3.2(vm_call0_body+0x5df) [0x70aa64d4c5cf] ruby-3.2.2/vm_eval.c:274 ruby-3.2.2/lib/libruby.so.3.2(vm_call0_cc+0x77) [0x70aa64d4e7e7] ruby-3.2.2/vm_eval.c:87 ruby-3.2.2/lib/libruby.so.3.2(rb_call0) ruby-3.2.2/vm_eval.c:551 ruby-3.2.2/lib/libruby.so.3.2(rb_call+0x32) [0x70aa64d4f406] ruby-3.2.2/vm_eval.c:877 ruby-3.2.2/lib/libruby.so.3.2(rb_funcallv_kw) ruby-3.2.2/vm_eval.c:1074 ruby-3.2.2/lib/libruby.so.3.2(rb_eval_cmd_kw+0x142) [0x70aa64d4f562] ruby-3.2.2/vm_eval.c:1923 ruby-3.2.2/lib/libruby.so.3.2(signal_exec+0xf6) [0x70aa64caae16] ruby-3.2.2/signal.c:1064 ruby-3.2.2/lib/libruby.so.3.2(rb_threadptr_execute_interrupts+0x36b) [0x70aa64cf7078] ruby-3.2.2/thread.c:2334 ruby-3.2.2/lib/libruby.so.3.2(rb_threadptr_execute_interrupts) ruby-3.2.2/thread.c:2291 ruby-3.2.2/lib/libruby.so.3.2(rb_vm_check_ints+0xb) [0x70aa64cf7ac5] ruby-3.2.2/vm_core.h:1994 ruby-3.2.2/lib/libruby.so.3.2(rb_vm_check_ints) ruby-3.2.2/vm_core.h:1985 ruby-3.2.2/lib/libruby.so.3.2(unblock_function_set) ruby-3.2.2/thread.c:320 ruby-3.2.2/lib/libruby.so.3.2(blocking_region_begin) ruby-3.2.2/thread.c:1485 ruby-3.2.2/lib/libruby.so.3.2(rb_nogvl+0xbf) [0x70aa64cf90cf] ruby-3.2.2/thread.c:1548 signal-bug-testcase-2/lib/signal_bug_testcase.so(fprintf+0x0) [0x70aa6518f299] ../../../../ext/signal_bug_testcase/signal_bug_testcase.c:17 signal-bug-testcase-2/lib/signal_bug_testcase.so(bug_testcase_free) ../../../../ext/signal_bug_testcase/signal_bug_testcase.c:18 ruby-3.2.2/lib/libruby.so.3.2(run_final+0xf) [0x70aa64b73172] ruby-3.2.2/gc.c:4388 ruby-3.2.2/lib/libruby.so.3.2(finalize_list) ruby-3.2.2/gc.c:4407 ruby-3.2.2/lib/libruby.so.3.2(finalize_deferred_heap_pages) ruby-3.2.2/gc.c:4436 ruby-3.2.2/lib/libruby.so.3.2(rb_objspace_call_finalizer+0x350) [0x70aa64b80d70] ruby-3.2.2/gc.c:4573 ruby-3.2.2/lib/libruby.so.3.2(rb_ec_finalize+0x2a) [0x70aa64b5d6d1] ruby-3.2.2/eval.c:168 ruby-3.2.2/lib/libruby.so.3.2(rb_ec_cleanup) ruby-3.2.2/eval.c:262 ruby-3.2.2/lib/libruby.so.3.2(ruby_run_node+0x9d) [0x70aa64b5d91d] ruby-3.2.2/eval.c:330 ruby-3.2.2/bin/ruby(rb_main+0x21) [0x5d5d1295f187] ./main.c:38 ruby-3.2.2/bin/ruby(main) ./main.c:57 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_call_main+0x80) [0x70aa64629d90] ../sysdeps/nptl/libc_start_call_main.h:58 /lib/x86_64-linux-gnu/libc.so.6(call_init+0x0) [0x70aa64629e40] ../csu/libc-start.c:392 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main_impl) ../csu/libc-start.c:379 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main) (null):0 [0x5d5d1295f1d5] ``` ---Files-------------------------------- signal-bug-testcase-main.zip (7.73 KB) -- https://bugs.ruby-lang.org/
3 4
0 0
  • ← Newer
  • 1
  • 2
  • 3
  • 4
  • ...
  • 21
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.