summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <[email protected]>2024-02-21 17:42:23 -0500
committerGitHub <[email protected]>2024-02-21 14:42:23 -0800
commit0be09967fee9eda531260e027094d619e034c425 (patch)
tree556f29ce44d65e98c690094700dc159d79a5b14e
parent551f64745fa0ba0ea70812f63495f2fa7dd5afe4 (diff)
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.
-rw-r--r--test/ruby/test_yjit.rb6
-rw-r--r--yjit/src/codegen.rs11
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);