diff options
author | Alan Wu <[email protected]> | 2021-05-21 12:13:55 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-21 12:13:55 -0400 |
commit | b2fc592c3046e60fdfbb5692d52cc7cbf814b6d0 (patch) | |
tree | f38d97fe181933560c58be574b8561cc48d602c6 /compile.c | |
parent | 0772f1b583cedebddb493a8eb542243f6d2437d8 (diff) |
Build CDHASH properly when loading iseq from binary
Before this change, CDHASH operands were built as plain hashes when
loaded from binary. Without setting up the hash with the correct
st_table type, the hash can sometimes be an ar_table. When the hash is
an ar_table, lookups can call the `eql?` method on keys of the hash,
which makes the `opt_case_dispatch` instruction not "leaf" as it
implicitly declares.
The following script trips the stack canary for checking the leaf
attribute for `opt_case_dispatch` on VM_CHECK_MODE > 0 (enabled by
default with RUBY_DEBUG).
rb_vm_iseq = RubyVM::InstructionSequence
iseq = rb_vm_iseq.compile(<<-EOF)
case Class.new(String).new("foo")
when "foo"
42
end
EOF
puts rb_vm_iseq.load_from_binary(iseq.to_binary).eval
This commit changes the binary loading logic to build CDHASH with the
right st_table type. The dumping logic and the dump format stays the
same
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4511
Merged-By: XrXr
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 15 |
1 files changed, 14 insertions, 1 deletions
@@ -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); |