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.
This commit is contained in:
Alan Wu 2024-02-21 17:42:23 -05:00 коммит произвёл GitHub
Родитель 551f64745f
Коммит 0be09967fe
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 12 добавлений и 5 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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);