From e4295bc3f763d220a944ed353eaeda2c1c1b88cd Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 13 Nov 2025 12:01:55 -0800 Subject: YJIT: Fix stack handling in rb_str_dup Previously because we did a stack_push before ccall, in some cases we could end up pushing an uninitialized value to the VM stack when spilling regs as part of the ccall. Co-authored-by: Luke Gruber --- bootstraptest/test_yjit.rb | 11 +++++++++++ yjit/src/codegen.rs | 6 ++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index 267bc09b75..94bda9951e 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -5369,3 +5369,14 @@ assert_equal 'false', %{ RESULT.any? } + +# throw and String#dup with GC stress +assert_equal 'foo', %{ + GC.stress = true + + def foo + 1.times { return "foo".dup } + end + + 10.times.map { foo.dup }.last +} diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 3f6f1bb46e..6c42dd1713 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -6168,7 +6168,7 @@ fn jit_rb_str_dup( jit_prepare_call_with_gc(jit, asm); - let recv_opnd = asm.stack_pop(1); + let recv_opnd = asm.stack_opnd(0); let recv_opnd = asm.load(recv_opnd); let shape_id_offset = unsafe { rb_shape_id_offset() }; @@ -6177,8 +6177,10 @@ fn jit_rb_str_dup( asm.jnz(Target::side_exit(Counter::send_str_dup_exivar)); // Call rb_str_dup - let stack_ret = asm.stack_push(Type::CString); let ret_opnd = asm.ccall(rb_str_dup as *const u8, vec![recv_opnd]); + + asm.stack_pop(1); + let stack_ret = asm.stack_push(Type::CString); asm.mov(stack_ret, ret_opnd); true -- cgit v1.2.3