summaryrefslogtreecommitdiff
path: root/test/ruby
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2022-04-29 18:54:16 -0400
committerAlan Wu <XrXr@users.noreply.github.com>2022-05-30 13:54:22 -0400
commita687756284187887835aa345adc89b2718054e4a (patch)
tree19593deccf5df5fe758c1f9a00b616c54ec99e02 /test/ruby
parent3bef9584a879e8e29baf8e7a67383679d1ffb725 (diff)
downloadruby-a687756284187887835aa345adc89b2718054e4a.tar.gz
Fix use-after-free with interacting TracePoints
`vm_trace_hook()` runs global hooks before running local hooks. Previously, we read the local hook list before running the global hooks which led to use-after-free when a global hook frees the local hook list. A global hook can do this by disabling a local TracePoint, for example. Delay local hook list loading until after running the global hooks. Issue discovered by Jeremy Evans in GH-5862. [Bug #18730]
Diffstat (limited to 'test/ruby')
-rw-r--r--test/ruby/test_gc_compact.rb17
-rw-r--r--test/ruby/test_settracefunc.rb14
2 files changed, 31 insertions, 0 deletions
diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb
index da0023e6f3..be27199cdc 100644
--- a/test/ruby/test_gc_compact.rb
+++ b/test/ruby/test_gc_compact.rb
@@ -200,4 +200,21 @@ class TestGCCompact < Test::Unit::TestCase
GC.compact
assert_equal count + 1, GC.stat(:compact_count)
end
+
+ def test_compacting_from_trace_point
+ obj = Object.new
+ def obj.tracee
+ :ret # expected to emit both line and call event from one instruction
+ end
+
+ results = []
+ TracePoint.new(:call, :line) do |tp|
+ results << tp.event
+ GC.verify_compaction_references
+ end.enable(target: obj.method(:tracee)) do
+ obj.tracee
+ end
+
+ assert_equal([:call, :line], results)
+ end
end
diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
index b43f9c114d..37c8b37c59 100644
--- a/test/ruby/test_settracefunc.rb
+++ b/test/ruby/test_settracefunc.rb
@@ -2561,6 +2561,20 @@ CODE
end
bar
EOS
+
+ assert_normal_exit(<<-EOS, 'Bug #18730')
+ def bar
+ 42
+ end
+ tp_line = TracePoint.new(:line) do |tp0|
+ tp_multi1 = TracePoint.new(:return, :b_return, :line) do |tp|
+ tp0.disable
+ end
+ tp_multi1.enable
+ end
+ tp_line.enable(target: method(:bar))
+ bar
+ EOS
end
def test_stat_exists