Skip to content

Commit 6ca43e9

Browse files
XrXrtenderlove
authored andcommitted
Push a real iseq in rb_vm_push_frame_fname()
Previously, vm_make_env_each() (used during proc creation and for the debug inspector C API) picked up the non-GC-allocated iseq that rb_vm_push_frame_fname() creates, which led to a SEGV when the GC tried to mark the non GC object. Put a real iseq imemo instead. Speed should be about the same since the old code also did a imemo allocation and a malloc allocation. Real iseq allows ironing out the special-casing of dummy frames in rb_execution_context_mark() and rb_execution_context_update(). A check is added to RubyVM::ISeq#eval, though, to stop attempts to run dummy iseqs. [Bug #21180] Co-authored-by: Aaron Patterson <[email protected]>
1 parent 31502b0 commit 6ca43e9

File tree

4 files changed

+58
-39
lines changed

4 files changed

+58
-39
lines changed

iseq.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,19 @@ rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
539539
rb_iseq_pathobj_new(path, realpath));
540540
}
541541

542+
// Make a dummy iseq for a dummy frame that exposes a path for profilers to inspect
543+
rb_iseq_t *
544+
rb_iseq_alloc_with_dummy_path(VALUE fname)
545+
{
546+
rb_iseq_t *dummy_iseq = iseq_alloc();
547+
548+
ISEQ_BODY(dummy_iseq)->type = ISEQ_TYPE_TOP;
549+
RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.pathobj, fname);
550+
RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.label, fname);
551+
552+
return dummy_iseq;
553+
}
554+
542555
static rb_iseq_location_t *
543556
iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_code_location_t *code_location, const int node_id)
544557
{
@@ -1917,7 +1930,11 @@ rb_iseqw_to_iseq(VALUE iseqw)
19171930
static VALUE
19181931
iseqw_eval(VALUE self)
19191932
{
1920-
return rb_iseq_eval(iseqw_check(self));
1933+
const rb_iseq_t *iseq = iseqw_check(self);
1934+
if (0 == ISEQ_BODY(iseq)->iseq_size) {
1935+
rb_raise(rb_eTypeError, "attempt to evaluate dummy InstructionSequence");
1936+
}
1937+
return rb_iseq_eval(iseq);
19211938
}
19221939

19231940
/*

test/fiber/test_scheduler.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,19 @@ def test_autoload
139139
end
140140
end
141141

142+
def test_iseq_compile_under_gc_stress_bug_21180
143+
Thread.new do
144+
scheduler = Scheduler.new
145+
Fiber.set_scheduler scheduler
146+
147+
Fiber.schedule do
148+
EnvUtil.under_gc_stress do
149+
RubyVM::InstructionSequence.compile_file(File::NULL)
150+
end
151+
end
152+
end.join
153+
end
154+
142155
def test_deadlock
143156
mutex = Thread::Mutex.new
144157
condition = Thread::ConditionVariable.new

vm.c

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3367,22 +3367,20 @@ rb_execution_context_update(rb_execution_context_t *ec)
33673367
}
33683368

33693369
while (cfp != limit_cfp) {
3370-
if (VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_DUMMY) {
3371-
const VALUE *ep = cfp->ep;
3372-
cfp->self = rb_gc_location(cfp->self);
3373-
cfp->iseq = (rb_iseq_t *)rb_gc_location((VALUE)cfp->iseq);
3374-
cfp->block_code = (void *)rb_gc_location((VALUE)cfp->block_code);
3375-
3376-
if (!VM_ENV_LOCAL_P(ep)) {
3377-
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
3378-
if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) {
3379-
VM_FORCE_WRITE(&prev_ep[VM_ENV_DATA_INDEX_ENV], rb_gc_location(prev_ep[VM_ENV_DATA_INDEX_ENV]));
3380-
}
3370+
const VALUE *ep = cfp->ep;
3371+
cfp->self = rb_gc_location(cfp->self);
3372+
cfp->iseq = (rb_iseq_t *)rb_gc_location((VALUE)cfp->iseq);
3373+
cfp->block_code = (void *)rb_gc_location((VALUE)cfp->block_code);
3374+
3375+
if (!VM_ENV_LOCAL_P(ep)) {
3376+
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
3377+
if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) {
3378+
VM_FORCE_WRITE(&prev_ep[VM_ENV_DATA_INDEX_ENV], rb_gc_location(prev_ep[VM_ENV_DATA_INDEX_ENV]));
3379+
}
33813380

3382-
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)) {
3383-
VM_FORCE_WRITE(&ep[VM_ENV_DATA_INDEX_ENV], rb_gc_location(ep[VM_ENV_DATA_INDEX_ENV]));
3384-
VM_FORCE_WRITE(&ep[VM_ENV_DATA_INDEX_ME_CREF], rb_gc_location(ep[VM_ENV_DATA_INDEX_ME_CREF]));
3385-
}
3381+
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)) {
3382+
VM_FORCE_WRITE(&ep[VM_ENV_DATA_INDEX_ENV], rb_gc_location(ep[VM_ENV_DATA_INDEX_ENV]));
3383+
VM_FORCE_WRITE(&ep[VM_ENV_DATA_INDEX_ME_CREF], rb_gc_location(ep[VM_ENV_DATA_INDEX_ME_CREF]));
33863384
}
33873385
}
33883386

@@ -3418,21 +3416,19 @@ rb_execution_context_mark(const rb_execution_context_t *ec)
34183416
const VALUE *ep = cfp->ep;
34193417
VM_ASSERT(!!VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED) == vm_ep_in_heap_p_(ec, ep));
34203418

3421-
if (VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_DUMMY) {
3422-
rb_gc_mark_movable(cfp->self);
3423-
rb_gc_mark_movable((VALUE)cfp->iseq);
3424-
rb_gc_mark_movable((VALUE)cfp->block_code);
3419+
rb_gc_mark_movable(cfp->self);
3420+
rb_gc_mark_movable((VALUE)cfp->iseq);
3421+
rb_gc_mark_movable((VALUE)cfp->block_code);
34253422

3426-
if (!VM_ENV_LOCAL_P(ep)) {
3427-
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
3428-
if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) {
3429-
rb_gc_mark_movable(prev_ep[VM_ENV_DATA_INDEX_ENV]);
3430-
}
3423+
if (!VM_ENV_LOCAL_P(ep)) {
3424+
const VALUE *prev_ep = VM_ENV_PREV_EP(ep);
3425+
if (VM_ENV_FLAGS(prev_ep, VM_ENV_FLAG_ESCAPED)) {
3426+
rb_gc_mark_movable(prev_ep[VM_ENV_DATA_INDEX_ENV]);
3427+
}
34313428

3432-
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)) {
3433-
rb_gc_mark_movable(ep[VM_ENV_DATA_INDEX_ENV]);
3434-
rb_gc_mark(ep[VM_ENV_DATA_INDEX_ME_CREF]);
3435-
}
3429+
if (VM_ENV_FLAGS(ep, VM_ENV_FLAG_ESCAPED)) {
3430+
rb_gc_mark_movable(ep[VM_ENV_DATA_INDEX_ENV]);
3431+
rb_gc_mark(ep[VM_ENV_DATA_INDEX_ME_CREF]);
34363432
}
34373433
}
34383434

vm_insnhelper.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -469,15 +469,8 @@ rb_vm_pop_frame(rb_execution_context_t *ec)
469469
VALUE
470470
rb_vm_push_frame_fname(rb_execution_context_t *ec, VALUE fname)
471471
{
472-
VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
473-
void *ptr = ruby_xcalloc(sizeof(struct rb_iseq_constant_body) + sizeof(struct rb_iseq_struct), 1);
474-
rb_imemo_tmpbuf_set_ptr(tmpbuf, ptr);
475-
476-
struct rb_iseq_struct *dmy_iseq = (struct rb_iseq_struct *)ptr;
477-
struct rb_iseq_constant_body *dmy_body = (struct rb_iseq_constant_body *)&dmy_iseq[1];
478-
dmy_iseq->body = dmy_body;
479-
dmy_body->type = ISEQ_TYPE_TOP;
480-
dmy_body->location.pathobj = fname;
472+
rb_iseq_t *rb_iseq_alloc_with_dummy_path(VALUE fname);
473+
rb_iseq_t *dmy_iseq = rb_iseq_alloc_with_dummy_path(fname);
481474

482475
vm_push_frame(ec,
483476
dmy_iseq, //const rb_iseq_t *iseq,
@@ -490,7 +483,7 @@ rb_vm_push_frame_fname(rb_execution_context_t *ec, VALUE fname)
490483
0, // int local_size,
491484
0); // int stack_max
492485

493-
return tmpbuf;
486+
return (VALUE)dmy_iseq;
494487
}
495488

496489
/* method dispatch */

0 commit comments

Comments
 (0)