summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_yjit.rb41
-rw-r--r--yjit/src/codegen.rs4
2 files changed, 43 insertions, 2 deletions
diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index 3ab04f6fe9..7f0f691320 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -1155,6 +1155,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
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index da87104ef6..e4cfe16e73 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -489,8 +489,8 @@ pub fn jit_ensure_block_entry_exit(jit: &mut JITState, ocb: &mut OutlinedCb) {
// Generate the exit with the cache in jitstate.
block.entry_exit = Some(get_side_exit(jit, ocb, &block_ctx).unwrap_code_ptr());
} else {
- let _pc = unsafe { rb_iseq_pc_at_idx(blockid.iseq, blockid.idx) };
- block.entry_exit = Some(gen_outlined_exit(jit.pc, &block_ctx, ocb));
+ let block_entry_pc = unsafe { rb_iseq_pc_at_idx(blockid.iseq, blockid.idx) };
+ block.entry_exit = Some(gen_outlined_exit(block_entry_pc, &block_ctx, ocb));
}
}