From 997a70f85994ac890b749e920cac8becf4b7f5ba Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Tue, 24 Aug 2021 14:43:07 +0900 Subject: [PATCH] Make it more robust against a spoofed filename Currently, RubyVM::AST.of attempts to reopen a file based on iseq's file path. However, it opens a wrong file if the iseq's file path is spoofed. ``` module Dummy binding.irb end ``` ``` $ ruby test.rb From: test.rb @ line 2 : 1: module Dummy => 2: binding.irb 3: end irb(Dummy):001:0> foo /home/mame/work/ruby/local/lib/ruby/3.1.0/error_highlight/base.rb:412:in `spot_colon2': undefined method `last_lineno' for nil:NilClass (NoMethodError) if nd_parent.last_lineno == @node.last_lineno ^^^^^^^^^^^^ ``` Found by @kateinoigakukun Though this is a fundamental design issue of RubyVM::AST.of, in any way it would be good to make error_highlight robust for unexpected exception. In a long term, this particular issue would be fixed by adding to irb an option `RubyVM::ISeq.keep_script_lines = true` (which is not implemented yet). --- lib/error_highlight/core_ext.rb | 2 +- test/test_error_highlight.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/error_highlight/core_ext.rb b/lib/error_highlight/core_ext.rb index 1ae180a..1066732 100644 --- a/lib/error_highlight/core_ext.rb +++ b/lib/error_highlight/core_ext.rb @@ -29,7 +29,7 @@ def to_s spot = ErrorHighlight.spot(node, **opts) - rescue Errno::ENOENT, SyntaxError + rescue StandardError, SyntaxError end if spot diff --git a/test/test_error_highlight.rb b/test/test_error_highlight.rb index 9fc1420..08ae68d 100644 --- a/test/test_error_highlight.rb +++ b/test/test_error_highlight.rb @@ -1194,4 +1194,22 @@ def test_no_final_newline end end end + + def test_spoofed_filename + Tempfile.create(["error_highlight_test", ".rb"], binmode: true) do |tmp| + tmp << "module Dummy\nend\n" + tmp.close + + assert_error_message(NameError, <<~END) do + undefined local variable or method `foo' for "dummy":String + END + + "dummy".instance_eval do + eval <<-END, nil, tmp.path + foo + END + end + end + end + end end