Bug #22257
closedPrepending a module to an already-included module leaves stale super caches
Description
When a module is prepended to a module that already has includers, super call sites inside the prepended module keep calling the old method entry after the method is redefined.
module M; def foo; :m; end; end
class D; include M; end
M.prepend(Module.new { def foo; super; end })
D.new.foo # prime the super call-site cache
M.send(:define_method, :foo) { :hooked }
p D.new.foo
I found this while working on an unrelated Ractor issue. But this problem manifests itself for Ractors as follows:
Ractor.new {}
require 'set'
Kernel.send(:define_method, :require) { |f| $hook = f }
require 'set'
p $hook # => nil, the hook never runs
This is because creating the first Ractor prepends an internal RactorRequire wrapper onto Kernel. After the first require primes the cache in the wrapper, redefining Kernel#require silently does nothing.
The linked PR fixes this by registering the backfilled iclass in the module's subclasses list, after the includer walk finishes.
Updated by eightbitraptor (Matt V-H) 4 days ago
Updated by eightbitraptor (Matt V-H) 3 days ago
- Status changed from Open to Closed
Applied in changeset git|06611602a958ebe1126be3a5cb151f3c2c8bffcc.
[Backport #22257] Fix stale super cache on prepend after include
Prepending a module to a module that already has includers backfills an
origin iclass into each includer's ancestor chain using rb_prepend_module.
The backfilled iclass is never added to a subclasses list, so
rb_clear_method_cache can't reach it when one of the module's methods is
later redefined.
Calling super through a call site that has cached the backfilled iclass
calls the old entry, even though it should be redefined.
module M; def foo; :m; end; end
class D; include M; end
M.prepend(Module.new { def foo; super; end })
D.new.foo # prime the super cache
M.send(:define_method, :foo) { :hooked }
D.new.foo # => got :m, expected :hooked
This commit makes sure that the backfilled iclass is registered in the
subclasses list.