Actions
Bug #22257
closedPrepending a module to an already-included module leaves stale super caches
Bug #22257:
Prepending a module to an already-included module leaves stale super caches
ruby -v:
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.
Actions