summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hawthorn <john@hawthorn.email>2025-11-13 12:01:55 -0800
committerJohn Hawthorn <john@hawthorn.email>2025-11-14 09:29:09 -0800
commite4295bc3f763d220a944ed353eaeda2c1c1b88cd (patch)
tree542fc510632b4aff8b510b16520484a7f4d886b2
parent286e326299bffdc4061565162502f6c76caf1189 (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.rb11
-rw-r--r--yjit/src/codegen.rs6
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