From 0be09967fee9eda531260e027094d619e034c425 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Wed, 21 Feb 2024 17:42:23 -0500 Subject: [PATCH] YJIT: Grab stack operands after SP change in String#byteslice (#10060) Previously, `StackOperand`s caching `sp_offset` was held across a jit_prepare_call_with_gc(), which invalidates the offsets. With the right register allocation state, the canary overlapped with the old address of the receiver and YJIT clobbered the receiver writing the canary. --- test/ruby/test_yjit.rb | 6 ++++++ yjit/src/codegen.rs | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index 35036aad4e..8936e567d1 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -1594,6 +1594,12 @@ class TestYJIT < Test::Unit::TestCase RUBY end + def test_byteslice_sp_invalidation + assert_compiles(<<~'RUBY', result: 'ok', no_send_fallbacks: true) + "okng".itself.byteslice(0, 2) + RUBY + end + private def code_gc_helpers diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 0064ed15cc..5e9d42de62 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -5398,12 +5398,8 @@ fn jit_rb_str_byteslice( return false } - let len = asm.stack_opnd(0); - let beg = asm.stack_opnd(1); - let recv = asm.stack_opnd(2); - // rb_str_byte_substr should be leaf if indexes are fixnums - match (asm.ctx.get_opnd_type(beg.into()), asm.ctx.get_opnd_type(len.into())) { + match (asm.ctx.get_opnd_type(StackOpnd(0)), asm.ctx.get_opnd_type(StackOpnd(1))) { (Type::Fixnum, Type::Fixnum) => {}, // Raises when non-integers are passed in, which requires the method frame // to be pushed for the backtrace @@ -5414,6 +5410,11 @@ fn jit_rb_str_byteslice( // rb_str_byte_substr allocates a substring jit_prepare_call_with_gc(jit, asm); + // Get stack operands after potential SP change + let len = asm.stack_opnd(0); + let beg = asm.stack_opnd(1); + let recv = asm.stack_opnd(2); + let ret_opnd = asm.ccall(rb_str_byte_substr as *const u8, vec![recv, beg, len]); asm.stack_pop(3);