summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2021-12-14 19:47:42 -0500
committerGitHub <noreply@github.com>2021-12-14 19:47:42 -0500
commitac5d6faea8e8d142df798572b0522f8a185c8fb6 (patch)
tree137e03d3cf33db4a7377daa073e59330526b7d41
parent6eb500e2df17475a557de536ce24a4d878bf1607 (diff)
YJIT: Fix unexpected truncation when outputing VALUE
Previously, YJIT incorrectly discarded the upper 32 bits of the object pointer when writing out VALUEs to setup default keyword arguments. In addition to incorrectly truncating, the output pointers were not properly tracked for handling GC compaction moving the referenced objects. YJIT previously attempted to encode a mov instruction with a memory destination and a 64 bit immediate when there is no such encoding possible in the ISA. Add an assert to mitigate not being able to catch this at build time.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/5274 Merged-By: XrXr
-rw-r--r--bootstraptest/test_yjit.rb15
-rw-r--r--yjit_asm.c5
-rw-r--r--yjit_codegen.c6
3 files changed, 23 insertions, 3 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index 2ac37df0a2..0b2b78ca4a 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1,3 +1,18 @@
+assert_equal '18374962167983112447', %q{
+ # regression test for incorrectly discarding 32 bits of a pointer when it
+ # comes to default values.
+ def large_literal_default(n: 0xff00_fabcafe0_00ff)
+ n
+ end
+
+ def call_graph_root
+ large_literal_default
+ end
+
+ call_graph_root
+ call_graph_root
+}
+
assert_normal_exit %q{
# regression test for a leak caught by an asert on --yjit-call-threshold=2
Foo = 1
diff --git a/yjit_asm.c b/yjit_asm.c
index 3a43c80ef0..64cbb163a2 100644
--- a/yjit_asm.c
+++ b/yjit_asm.c
@@ -1343,7 +1343,10 @@ void mov(codeblock_t *cb, x86opnd_t dst, x86opnd_t src)
else
cb_write_rm(cb, dst.num_bits == 16, dst.num_bits == 64, NO_OPND, dst, 0, 1, 0xC7);
- cb_write_int(cb, src.as.imm, (dst.num_bits > 32)? 32:dst.num_bits);
+ const uint32_t output_num_bits = (dst.num_bits > 32u) ? 32u : dst.num_bits;
+ // assert that we can write whole immediate without loss of infomation
+ assert (sig_imm_size(src.as.imm) <= output_num_bits);
+ cb_write_int(cb, src.as.imm, output_num_bits);
}
else
diff --git a/yjit_codegen.c b/yjit_codegen.c
index 3378f1500d..38b830a097 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -3698,7 +3698,7 @@ gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const r
// This struct represents the metadata about the callee-specified
// keyword parameters.
- const struct rb_iseq_param_keyword *keyword = iseq->body->param.keyword;
+ const struct rb_iseq_param_keyword *const keyword = iseq->body->param.keyword;
ADD_COMMENT(cb, "keyword args");
@@ -3748,7 +3748,9 @@ gen_send_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const r
default_value = Qnil;
}
- mov(cb, default_arg, imm_opnd(default_value));
+ // GC might move default_value.
+ jit_mov_gc_ptr(jit, cb, REG0, default_value);
+ mov(cb, default_arg, REG0);
caller_kwargs[kwarg_idx++] = callee_kwarg;
}