Skip to content

Commit 1bb15bd

Browse files
luke-gruberpeterzhu2118
authored andcommitted
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 b6d0961 commit 1bb15bd

1 file changed

Lines changed: 19 additions & 17 deletions

File tree

variable.c

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

37183718
rb_check_frozen(mod);
37193719

3720-
ce = rb_const_lookup(mod, id);
3721-
if (!ce || !rb_id_table_delete(RCLASS_WRITABLE_CONST_TBL(mod), id)) {
3722-
if (rb_const_defined_at(mod, id)) {
3723-
rb_name_err_raise("cannot remove %2$s::%1$s", mod, ID2SYM(id));
3724-
}
3720+
RB_VM_LOCKING() {
3721+
ce = rb_const_lookup(mod, id);
3722+
if (!ce || !rb_id_table_delete(RCLASS_WRITABLE_CONST_TBL(mod), id)) {
3723+
if (rb_const_defined_at(mod, id)) {
3724+
rb_name_err_raise("cannot remove %2$s::%1$s", mod, ID2SYM(id));
3725+
}
37253726

3726-
undefined_constant(mod, ID2SYM(id));
3727-
}
3727+
undefined_constant(mod, ID2SYM(id));
3728+
}
37283729

3729-
rb_const_warn_if_deprecated(ce, mod, id);
3730-
rb_clear_constant_cache_for_id(id);
3730+
rb_const_warn_if_deprecated(ce, mod, id);
3731+
rb_clear_constant_cache_for_id(id);
37313732

3732-
val = ce->value;
3733+
val = ce->value;
37333734

3734-
if (UNDEF_P(val)) {
3735-
autoload_delete(mod, id);
3736-
val = Qnil;
3737-
}
3735+
if (UNDEF_P(val)) {
3736+
autoload_delete(mod, id);
3737+
val = Qnil;
3738+
}
37383739

3739-
if (ce != const_lookup(RCLASS_PRIME_CONST_TBL(mod), id)) {
3740-
ruby_xfree(ce);
3740+
if (ce != const_lookup(RCLASS_PRIME_CONST_TBL(mod), id)) {
3741+
ruby_xfree(ce);
3742+
}
3743+
// else - skip free'ing the ce because it still exists in the prime classext
37413744
}
3742-
// else - skip free'ing the ce because it still exists in the prime classext
37433745

37443746
return val;
37453747
}

0 commit comments

Comments
 (0)