Skip to content

Commit

Permalink
Fix missing write barrier in iseq instruction list
Browse files Browse the repository at this point in the history
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"
```
  • Loading branch information
peterzhu2118 committed Sep 6, 2023
1 parent a52ac35 commit b3b57f7
Showing 1 changed file with 36 additions and 17 deletions.
53 changes: 36 additions & 17 deletions compile.c
Expand Up @@ -1282,6 +1282,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)
Expand All @@ -1299,6 +1325,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;
}

Expand Down Expand Up @@ -10735,6 +10764,12 @@ iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
return keyword;
}

static void
iseq_insn_each_object_mark_and_move(VALUE *obj_ptr, VALUE _)
{
rb_gc_mark_and_move(obj_ptr);
}

void
rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
{
Expand All @@ -10761,23 +10796,7 @@ rb_iseq_mark_and_move_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.
rb_gc_mark_and_move(&OPERAND_AT(iobj, j));
break;
default:
break;
}
}
iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
}
pos += (int)size;
}
Expand Down

0 comments on commit b3b57f7

Please sign in to comment.