diff --git a/lib/irb.rb b/lib/irb.rb index 168595d34..5cb91a293 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -992,6 +992,7 @@ def debug_readline(binding) def run(conf = IRB.conf) in_nested_session = !!conf[:MAIN_CONTEXT] conf[:IRB_RC].call(context) if conf[:IRB_RC] + prev_context = conf[:MAIN_CONTEXT] conf[:MAIN_CONTEXT] = context save_history = !in_nested_session && conf[:SAVE_HISTORY] && context.io.support_history_saving? @@ -1014,6 +1015,9 @@ def run(conf = IRB.conf) eval_input end ensure + # Do not restore to nil. It will cause IRB crash when used with threads. + IRB.conf[:MAIN_CONTEXT] = prev_context if prev_context + RubyVM.keep_script_lines = keep_script_lines_backup if defined?(RubyVM.keep_script_lines) trap("SIGINT", prev_trap) conf[:AT_EXIT].each{|hook| hook.call} diff --git a/test/irb/test_irb.rb b/test/irb/test_irb.rb index 84b9ee364..b05fc80f7 100644 --- a/test/irb/test_irb.rb +++ b/test/irb/test_irb.rb @@ -125,6 +125,26 @@ def test_empty_input_echoing_behaviour end end + class NestedBindingIrbTest < IntegrationTestCase + def test_current_context_restore + write_ruby <<~'RUBY' + binding.irb + RUBY + + output = run_ruby_file do + type '$ctx = IRB.CurrentContext' + type 'binding.irb' + type 'p context_changed: IRB.CurrentContext != $ctx' + type 'exit' + type 'p context_restored: IRB.CurrentContext == $ctx' + type 'exit' + end + + assert_include output, '{:context_changed=>true}' + assert_include output, '{:context_restored=>true}' + end + end + class IrbIOConfigurationTest < TestCase Row = Struct.new(:content, :current_line_spaces, :new_line_spaces, :indent_level)