From 0ba10fd8508b1a2bf7488649ee90622de9bef04a Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 16 Jul 2023 11:22:31 +0900 Subject: merge revision(s) 132934b82baad97107fe754d60f9a68a1db7ecda: [Backport #19463] YJIT: Generate Block::entry_exit with block entry PC Previously, when Block::entry_exit is requested from any instruction that is not the first one in the block, we generated the exit with an incorrect PC. We should always be using the PC for the entry of the block for Block::entry_exit. It was a simple typo. The bug was [introduced][1] while we were refactoring to use the current backend. Later, we had a chance to spot this issue while [preparing][2] to enable unused variable warnings, but didn't spot the issue. Fixes [Bug #19463] [1]: 27fcab995e6dde19deb91dc6e291bdb72100af68 [2]: 31461c7e0eab4963ccc8649ea8ebf27979132c0c --- test/ruby/test_yjit.rb | 41 +++++++++++++++++++++++++++++++++++++++++ yjit/src/codegen.rs | 4 ++-- 2 files changed, 43 insertions(+), 2 deletions(-) --- test/ruby/test_yjit.rb | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'test/ruby') diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index e4080595b0..5da42a1b6f 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -1141,6 +1141,47 @@ class TestYJIT < Test::Unit::TestCase RUBY end + def test_return_to_invalidated_block + # [Bug #19463] + assert_compiles(<<~RUBY, result: [1, 1, :ugokanai]) + klass = Class.new do + def self.lookup(hash, key) = hash[key] + + def self.foo(a, b) = [] + + def self.test(hash, key) + [lookup(hash, key), key, "".freeze] + # 05 opt_send_without_block :lookup + # 07 getlocal_WC_0 :hash + # 09 opt_str_freeze "" + # 12 newarray 3 + # 14 leave + # + # YJIT will put instructions (07..14) into a block. + # When String#freeze is redefined from within lookup(), + # the return address to the block is still on-stack. We rely + # on invalidation patching the code at the return address + # to service this situation correctly. + end + end + + # get YJIT to compile test() + hash = { 1 => [] } + 31.times { klass.test(hash, 1) } + + # inject invalidation into lookup() + evil_hash = Hash.new do |_, key| + class String + undef :freeze + def freeze = :ugokanai + end + + key + end + klass.test(evil_hash, 1) + RUBY + end + private def code_gc_helpers -- cgit v1.2.3