Bug #21991
closed`$!` stays as the first exception in Ruby Box
Description
Description¶
When Ruby Box is enabled (RUBY_BOX=1), $! inside rescue does not change after the first exception.
$! is expected to show the exception for each rescue block, but it always shows the first one.
Steps to reproduce¶
# test.rb
begin
raise "First error"
rescue
pp $!
end
begin
raise "Second error"
rescue
pp $!
end
begin
raise "Third error"
rescue
pp $!
end
Expected result¶
$ RUBY_BOX=1 ruby test.rb
ruby: warning: Ruby::Box is experimental, and the behavior may change in the future!
See https://docs.ruby-lang.org/en/4.0/Ruby/Box.html for known issues, etc.
#<RuntimeError: First error>
#<RuntimeError: Second error>
#<RuntimeError: Third error>
Actual result¶
$ RUBY_BOX=1 ruby test.rb
ruby: warning: Ruby::Box is experimental, and the behavior may change in the future!
See https://docs.ruby-lang.org/en/4.0/Ruby/Box.html for known issues, etc.
#<RuntimeError: First error>
#<RuntimeError: First error>
#<RuntimeError: First error>
Additional information¶
This issue does not reproduce when RUBY_BOX=1 is not set:
$ ruby test.rb
#<RuntimeError: First error>
#<RuntimeError: Second error>
#<RuntimeError: Third error>
Also, this issue does not reproduce when the exception object is captured explicitly in the rescue clause:
# test.rb
begin
raise "First error"
rescue => e
pp e
end
begin
raise "Second error"
rescue => e
pp e
end
begin
raise "Third error"
rescue => e
pp e
end
$ RUBY_BOX=1 ruby test.rb
ruby: warning: Ruby::Box is experimental, and the behavior may change in the future!
See https://docs.ruby-lang.org/en/4.0/Ruby/Box.html for known issues, etc.
#<RuntimeError: First error>
#<RuntimeError: Second error>
#<RuntimeError: Third error>
Updated by byroot (Jean Boussier) 27 days ago
- Related to Bug #21823: $! is nil inside rescue block when $! is accessed before raise in Ruby::Box added
Updated by byroot (Jean Boussier) 27 days ago
- Assignee set to tagomoris (Satoshi Tagomori)
Updated by dak2 (Daichi Kamiyama) 3 days ago
I created a patch for this issue.
https://github.com/ruby/ruby/pull/16863
@tagomoris (Satoshi Tagomori) Could you review this?
Updated by dak2 (Daichi Kamiyama) about 14 hours ago
- Status changed from Open to Closed
Applied in changeset git|d4727cd4e63c7bc1bc95a96b7f3c6de568bc5b6e.
Ruby::Box fix stale cached values for exception-related global variables ($! and $@)
Ruby::Box fix stale cached values for exception-related global variables ($! and $@)
The exception-related virtual variables $! (current exception) and
$@ (its backtrace) are stored on the execution context (ec->errinfo
and the rescue/ensure frame's local slot accessed via errinfo_place),
not in box->gvar_tbl. Caching their values in box->gvar_tbl makes the
second read return a stale value from the previous raise/rescue:
begin; raise "first"; rescue; p $!; end
begin; raise "second"; rescue; p $!; end
# before: #<RuntimeError: first> / #<RuntimeError: first>
# after: #<RuntimeError: first> / #<RuntimeError: second>
begin; raise "first"; rescue; p $@.first; end
begin; raise "second"; rescue; p $@.first; end
# before: same backtrace returned for both
# after: distinct backtrace per raise
Fixes Bug #21991
Related PR: https://github.com/ruby/ruby/pull/16303