diff options
| author | John Hawthorn <john@hawthorn.email> | 2025-11-13 12:01:55 -0800 |
|---|---|---|
| committer | John Hawthorn <john@hawthorn.email> | 2025-11-14 09:29:09 -0800 |
| commit | e4295bc3f763d220a944ed353eaeda2c1c1b88cd (patch) | |
| tree | 542fc510632b4aff8b510b16520484a7f4d886b2 | |
| parent | 286e326299bffdc4061565162502f6c76caf1189 (diff) | |
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 <luke.gru@gmail.com>
| -rw-r--r-- | bootstraptest/test_yjit.rb | 11 | ||||
| -rw-r--r-- | 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 |
