Fixing Kernel#singleton_method bug in Ruby.

Vasiliy Ermolovich
Apr 5, 2018 · 2 min read

Few days ago when I was browsing through StackOverflow I came across this question about weird behaviour of Kernel#singleton_method such as if you call Kernel#singleton_methods method on ActiveSupport::Deprecation class you would get you list of singleton methods (no surprise here) but when you try to get that singleton method with Kernel#singleton_method Ruby would throw NameError error:

At first, I thought it’s ActiveSupport doing something fishy. And while I was looking through AS codebase this answer appeared. @michaelj discovered that it's possible to reproduce this bug without ActiveSupport at all. All you needed to do is to prepend any module to a singleton class:

So it was something wrong with Module#prepend.

I started looking for some bugs with Module#prepend on Ruby's bugtracker. All I could find related was this bug with Object#methods and Module#prepend. So what I needed to do is to check how they fixed it and do something similar with Kernel#singleton_method.

DISCLAIMER: I’m not that good with Ruby internals so next part of the post might have some incorrect statements.

Main thing I learned from Object#methods fix was RCLASS_ORIGIN macro. This macro is used to get origin class of the passed class/module. And as I discovered Module#prepend makes a copy of a target class internally so if you need to access original one you can use that macro. Honestly, I don't really understand why you can't access singleton method but I got the idea.

That’s how rb_obj_singleton_method looked before the fix:

as you can see the klass was retrieved by rb_singleton_class_get function which returns class's copy if it was already prepended with some module. That means all I had to do is to apply RCLASS_ORIGIN on that class. And it did the trick. You can find the whole patch in this issue.

And may Ruby be with you.

hyperoslo

Hyper Labs

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store