mirror of
https://github.com/ruby/ruby.git
synced 2025-08-23 21:14:23 +02:00
[Backport 3.2] Fix missing write barrier in iseq instruction list (#8431)
Fix missing write barrier in iseq instruction list [Bug #19880] There's a missing write barrier for operands in the iseq instruction list, which can cause crashes. It can be reproduced when Ruby is compiled with `-DRUBY_DEBUG_ENV=1`. Using the following command: ``` RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=0 RUBY_DEBUG=gc_stress ruby -w --disable=gems -Itool/lib -W0 test.rb ``` The following script crashes: ``` require "test/unit" ```
This commit is contained in:
parent
e159971e03
commit
a7335e11e3
1 changed files with 36 additions and 23 deletions
59
compile.c
59
compile.c
|
@ -1243,6 +1243,32 @@ new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
|
|||
return adjust;
|
||||
}
|
||||
|
||||
static void
|
||||
iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
|
||||
{
|
||||
const char *types = insn_op_types(insn->insn_id);
|
||||
for (int j = 0; types[j]; j++) {
|
||||
char type = types[j];
|
||||
switch (type) {
|
||||
case TS_CDHASH:
|
||||
case TS_ISEQ:
|
||||
case TS_VALUE:
|
||||
case TS_IC: // constant path array
|
||||
case TS_CALLDATA: // ci is stored.
|
||||
func(&OPERAND_AT(insn, j), data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iseq_insn_each_object_write_barrier(VALUE *obj_ptr, VALUE iseq)
|
||||
{
|
||||
RB_OBJ_WRITTEN(iseq, Qundef, *obj_ptr);
|
||||
}
|
||||
|
||||
static INSN *
|
||||
new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
|
||||
int insn_id, int argc, VALUE *argv)
|
||||
|
@ -1260,6 +1286,9 @@ new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
|
|||
iobj->operands = argv;
|
||||
iobj->operand_size = argc;
|
||||
iobj->sc_state = 0;
|
||||
|
||||
iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
|
||||
|
||||
return iobj;
|
||||
}
|
||||
|
||||
|
@ -10735,6 +10764,12 @@ iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
|
|||
return keyword;
|
||||
}
|
||||
|
||||
static void
|
||||
iseq_insn_each_object_mark(VALUE *obj_ptr, VALUE _)
|
||||
{
|
||||
rb_gc_mark(*obj_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
|
||||
{
|
||||
|
@ -10761,29 +10796,7 @@ rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
|
|||
iobj = (INSN *)&storage->buff[pos];
|
||||
|
||||
if (iobj->operands) {
|
||||
int j;
|
||||
const char *types = insn_op_types(iobj->insn_id);
|
||||
|
||||
for (j = 0; types[j]; j++) {
|
||||
char type = types[j];
|
||||
switch (type) {
|
||||
case TS_CDHASH:
|
||||
case TS_ISEQ:
|
||||
case TS_VALUE:
|
||||
case TS_IC: // constant path array
|
||||
case TS_CALLDATA: // ci is stored.
|
||||
{
|
||||
VALUE op = OPERAND_AT(iobj, j);
|
||||
|
||||
if (!SPECIAL_CONST_P(op)) {
|
||||
rb_gc_mark(op);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark, (VALUE)0);
|
||||
}
|
||||
pos += (int)size;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue