Actions
Bug #19348
closedGVL being released earlier than expected when loading iseqs
Description
When using the debug
gem in a Rails app with Ruby 3.2, I noticed that if the VS Code editor connects to the debugger during the app boot, this error could occur:
DEBUGGER: ReaderThreadError: uninitialized InstructionSequence
┃ DEBUGGER: Disconnected.
┃ ["/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:247:in `absolute_path'",
┃ "/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:247:in `block in iterate_iseq'",
┃ "/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:246:in `each_iseq'",
...
After investigating it with @peterzhu2118 (Peter Zhu), we found that it's because:
- During the Rails app's boot time, it uses
bootsnap
to load iseqs, which uses theibf_load_iseq_each
function underneath. - After commit e35c528d721d209ed8531b10b46c2ac725ea7bf5 (added in 3.2), that function starts calling
rb_vm_pop_frame
at the end of execution. - Because
rb_vm_pop_frame
triggers the release of GVL, iseqs that just being loaded now become accessible by other threads, even though they're not ready to be used. - Now, if the
debug
gem callsObjectSpace.each_iseq
to activate aLineBreakpoint
from its own thread, it'd gain access to those unready iseqs and try to read their state, which would then cause theuninitialized InstructionSequence
error.
Actions
Like0
Like0Like0Like0