summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c15
-rw-r--r--test/ruby/test_iseq.rb13
2 files changed, 27 insertions, 1 deletions
diff --git a/compile.c b/compile.c
index d2de521ec8..44fb53cefd 100644
--- a/compile.c
+++ b/compile.c
@@ -10761,7 +10761,6 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
/* operands */
for (op_index=0; types[op_index]; op_index++, code_index++) {
switch (types[op_index]) {
- case TS_CDHASH:
case TS_VALUE:
{
VALUE op = ibf_load_small_value(load, &reading_pos);
@@ -10773,6 +10772,20 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
}
break;
}
+ case TS_CDHASH:
+ {
+ VALUE op = ibf_load_small_value(load, &reading_pos);
+ VALUE v = ibf_load_object(load, op);
+ v = rb_hash_dup(v); // hash dumped as frozen
+ RHASH_TBL_RAW(v)->type = &cdhash_type;
+ rb_hash_rehash(v); // hash function changed
+ freeze_hide_obj(v);
+
+ code[code_index] = v;
+ RB_OBJ_WRITTEN(iseqv, Qundef, v);
+ FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
+ break;
+ }
case TS_ISEQ:
{
VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index e3ca1ba926..0cde1fbb7a 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -82,6 +82,19 @@ class TestISeq < Test::Unit::TestCase
end;
end if defined?(RubyVM::InstructionSequence.load)
+ def test_cdhash_after_roundtrip
+ # CDHASH was not built properly when loading from binary and
+ # was causing opt_case_dispatch to clobber its stack canary
+ # for its "leaf" instruction attribute.
+ iseq = compile(<<~EOF)
+ case Class.new(String).new("foo")
+ when "foo"
+ 42
+ end
+ EOF
+ assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ end
+
def test_disasm_encoding
src = "\u{3042} = 1; \u{3042}; \u{3043}"
asm = compile(src).disasm