Module#remove_method: Check frozen on the right object

Previously, the frozen check happened on `RCLASS_ORIGIN(self)`, which
can return an iclass. The frozen check is supposed to respond to objects
that users can call methods on while iclasses are hidden from users.
Other mutation methods like Module#{define_method,alias_method,public}
don't do this. Check frozen status on the module itself.

Fixes [Bug #19164] and [Bug #19166].

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
This commit is contained in:
Jean byroot Boussier 2022-12-01 23:32:41 +01:00 committed by GitHub
parent 9da2a5204f
commit 3d272b0fc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2022-12-01 22:33:02 +00:00
Merged: https://github.com/ruby/ruby/pull/6842

Merged-By: XrXr
3 changed files with 22 additions and 1 deletions

View File

@ -809,4 +809,13 @@ PREP
3_000_000.times(&code)
CODE
end
def test_instance_freeze_dont_freeze_the_class_bug_19164
klass = Class.new
klass.prepend(Module.new)
klass.new.freeze
klass.define_method(:bar) {}
assert_equal klass, klass.remove_method(:bar), '[Bug #19164]'
end
end

View File

@ -2350,6 +2350,18 @@ class TestModule < Test::Unit::TestCase
assert_equal(:foo, removed)
end
def test_frozen_prepend_remove_method
[Module, Class].each do |klass|
mod = klass.new do
prepend(Module.new)
def foo; end
end
mod.freeze
assert_raise(FrozenError, '[Bug #19166]') { mod.send(:remove_method, :foo) }
assert_equal([:foo], mod.instance_methods(false))
end
end
def test_prepend_class_ancestors
bug6658 = '[ruby-core:45919]'
m = labeled_module("m")

View File

@ -1541,8 +1541,8 @@ remove_method(VALUE klass, ID mid)
rb_method_entry_t *me = 0;
VALUE self = klass;
klass = RCLASS_ORIGIN(klass);
rb_class_modify_check(klass);
klass = RCLASS_ORIGIN(klass);
if (mid == object_id || mid == id__send__ || mid == idInitialize) {
rb_warn("removing `%s' may cause serious problems", rb_id2name(mid));
}