Skip to content

Commit f062dbb

Browse files
committed
add VM Lock around rb_const_remove operations (Module#remove_const)
Without a VM Lock, there's an unlocked `rb_id_table_delete` for the class's const_tbl which can cause problems. Example: ```ruby class C CONSTANT = 3 end $VERBOSE = nil rs = [] 100.times do rs << Ractor.new do 10_000.times do if defined?(C::CONSTANT) C.send(:remove_const, :CONSTANT) rescue NameError else C.send(:const_set, :CONSTANT, 3) end end end end while rs.any? r, obj = Ractor.select(*rs) rs.delete(r) end ``` Without lock: ../ruby-release/test.rb:14: [BUG] Segmentation fault at 0x0000000000000001 -- Control frame information ----------------------------------------------- miniruby(82790,0x16f49f000) malloc: *** error for object 0x600000f880a0: pointer being freed was not allocated miniruby(82790,0x16f49f000) malloc: *** set a breakpoint in malloc_error_break to debug
1 parent ae04538 commit f062dbb

File tree

1 file changed

+19
-17
lines changed

1 file changed

+19
-17
lines changed

variable.c

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3671,29 +3671,31 @@ rb_const_remove(VALUE mod, ID id)
36713671

36723672
rb_check_frozen(mod);
36733673

3674-
ce = rb_const_lookup(mod, id);
3675-
if (!ce || !rb_id_table_delete(RCLASS_WRITABLE_CONST_TBL(mod), id)) {
3676-
if (rb_const_defined_at(mod, id)) {
3677-
rb_name_err_raise("cannot remove %2$s::%1$s", mod, ID2SYM(id));
3678-
}
3674+
RB_VM_LOCKING() {
3675+
ce = rb_const_lookup(mod, id);
3676+
if (!ce || !rb_id_table_delete(RCLASS_WRITABLE_CONST_TBL(mod), id)) {
3677+
if (rb_const_defined_at(mod, id)) {
3678+
rb_name_err_raise("cannot remove %2$s::%1$s", mod, ID2SYM(id));
3679+
}
36793680

3680-
undefined_constant(mod, ID2SYM(id));
3681-
}
3681+
undefined_constant(mod, ID2SYM(id));
3682+
}
36823683

3683-
rb_const_warn_if_deprecated(ce, mod, id);
3684-
rb_clear_constant_cache_for_id(id);
3684+
rb_const_warn_if_deprecated(ce, mod, id);
3685+
rb_clear_constant_cache_for_id(id);
36853686

3686-
val = ce->value;
3687+
val = ce->value;
36873688

3688-
if (UNDEF_P(val)) {
3689-
autoload_delete(mod, id);
3690-
val = Qnil;
3691-
}
3689+
if (UNDEF_P(val)) {
3690+
autoload_delete(mod, id);
3691+
val = Qnil;
3692+
}
36923693

3693-
if (ce != const_lookup(RCLASS_PRIME_CONST_TBL(mod), id)) {
3694-
ruby_xfree(ce);
3694+
if (ce != const_lookup(RCLASS_PRIME_CONST_TBL(mod), id)) {
3695+
ruby_xfree(ce);
3696+
}
3697+
// else - skip free'ing the ce because it still exists in the prime classext
36953698
}
3696-
// else - skip free'ing the ce because it still exists in the prime classext
36973699

36983700
return val;
36993701
}

0 commit comments

Comments
 (0)