From b95f680ae7e4d57d4b4f6eba9fcae11b27ff6fca Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Sun, 28 Oct 2018 11:45:00 -0400 Subject: [PATCH] Fix TracePoint for nested iseq loaded from binary [Bug #14702] When loading iseq from binary while a TracePoint is on, we need to recompile instructions to their "trace_" variant. Before this commit we only recompiled instructions in the top level iseq, which meant that TracePoint was malfunctioning for code inside module/class/method definitions. * compile.c: Move rb_iseq_init_trace to rb_ibf_load_iseq_complete. It is called on all iseqs during loading. * test_iseq.rb: Test that tracepoints fire within children iseq when using load_from_binary. --- compile.c | 3 +- test/ruby/test_iseq.rb | 77 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/compile.c b/compile.c index 7d221d5dee..4a8dffe37d 100644 --- a/compile.c +++ b/compile.c @@ -9883,6 +9883,7 @@ rb_ibf_load_iseq_complete(rb_iseq_t *iseq) ibf_load_iseq_each(load, iseq, offset); ISEQ_COMPILE_DATA_CLEAR(iseq); FL_UNSET(iseq, ISEQ_NOT_LOADED_YET); + rb_iseq_init_trace(iseq); load->iseq = prev_src_iseq; } @@ -10031,8 +10032,6 @@ rb_iseq_ibf_load(VALUE str) ibf_load_setup(load, loader_obj, str); iseq = ibf_load_iseq(load, 0); - rb_iseq_init_trace(iseq); - RB_GC_GUARD(loader_obj); return iseq; } diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index d193f41c6e..078c11472d 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -286,8 +286,12 @@ def test_inspect end end + def strip_lineno(source) + source.gsub(/^.*?: /, "") + end + def sample_iseq - ISeq.compile <<-EOS.gsub(/^.*?: /, "") + ISeq.compile(strip_lineno(<<-EOS)) 1: class C 2: def foo 3: begin @@ -439,17 +443,74 @@ def q; end end; end - def test_to_binary_tracepoint - filename = "#{File.basename(__FILE__)}_#{__LINE__}" - iseq = RubyVM::InstructionSequence.compile("x = 1\n y = 2", filename) + def collect_from_binary_tracepoint_lines(tracepoint_type, filename) + iseq = RubyVM::InstructionSequence.compile(strip_lineno(<<-RUBY), filename) + class A + class B + 2.times { + def self.foo + a = 'good day' + raise + rescue + 'dear reader' + end + } + end + B.foo + end + RUBY + iseq_bin = iseq.to_binary - ary = [] - TracePoint.new(:line){|tp| + lines = [] + TracePoint.new(tracepoint_type){|tp| next unless tp.path == filename - ary << [tp.path, tp.lineno] + lines << tp.lineno }.enable{ ISeq.load_from_binary(iseq_bin).eval } - assert_equal [[filename, 1], [filename, 2]], ary, '[Bug #14702]' + + lines + end + + def test_to_binary_line_tracepoint + filename = "#{File.basename(__FILE__)}_#{__LINE__}" + lines = collect_from_binary_tracepoint_lines(:line, filename) + + assert_equal [1, 2, 3, 4, 4, 12, 5, 6, 8], lines, '[Bug #14702]' + end + + def test_to_binary_class_tracepoint + filename = "#{File.basename(__FILE__)}_#{__LINE__}" + lines = collect_from_binary_tracepoint_lines(:class, filename) + + assert_equal [1, 2], lines, '[Bug #14702]' + end + + def test_to_binary_end_tracepoint + filename = "#{File.basename(__FILE__)}_#{__LINE__}" + lines = collect_from_binary_tracepoint_lines(:end, filename) + + assert_equal [11, 13], lines, '[Bug #14702]' + end + + def test_to_binary_return_tracepoint + filename = "#{File.basename(__FILE__)}_#{__LINE__}" + lines = collect_from_binary_tracepoint_lines(:return, filename) + + assert_equal [9], lines, '[Bug #14702]' + end + + def test_to_binary_b_call_tracepoint + filename = "#{File.basename(__FILE__)}_#{__LINE__}" + lines = collect_from_binary_tracepoint_lines(:b_call, filename) + + assert_equal [3, 3], lines, '[Bug #14702]' + end + + def test_to_binary_b_return_tracepoint + filename = "#{File.basename(__FILE__)}_#{__LINE__}" + lines = collect_from_binary_tracepoint_lines(:b_return, filename) + + assert_equal [10, 10], lines, '[Bug #14702]' end end -- 2.19.1