Skip to content

Commit

Permalink
Only detach the proc for "natural" Proc instances.
Browse files Browse the repository at this point in the history
This avoids detaching the object for user-provided singleton procs
where they may actually want the hard reference and hook callbacks
to work as before.

See jrubyGH-4968.
  • Loading branch information
headius authored and Adithya Pentela committed Aug 25, 2019
1 parent 7c22206 commit ef3f1e3
Showing 1 changed file with 9 additions and 3 deletions.
12 changes: 9 additions & 3 deletions core/src/main/java/org/jruby/javasupport/JavaUtil.java
Expand Up @@ -254,6 +254,10 @@ public static <T> T convertProcToInterface(ThreadContext context, RubyObject rub
public static <T> T convertProcToInterface(ThreadContext context, RubyBasicObject rubyObject, Class<T> targetType) {
final Ruby runtime = context.runtime;

// Capture original class; we only detach the singleton for natural Proc instances
RubyClass procClass = rubyObject.getMetaClass();

// Extend the interfaces into the proc's class. This creates a singleton class to connect up the Java proxy.
final RubyModule ifaceModule = Java.getInterfaceModule(runtime, JavaClass.get(runtime, targetType));
if ( ! ifaceModule.isInstance(rubyObject) ) {
ifaceModule.callMethod(context, "extend_object", rubyObject);
Expand All @@ -265,9 +269,11 @@ public static <T> T convertProcToInterface(ThreadContext context, RubyBasicObjec
// no matter what method is called on the interface
final RubyClass singletonClass = rubyObject.getSingletonClass();

// We clear the "attached" proc so the singleton class and by extension the method cache in the interface
// impl does not root the proc and its binding in the host classloader. See GH-4968.
((MetaClass) singletonClass).setAttached(singletonClass.getSuperClass());
if (procClass == runtime.getProc()) {
// We reattach the singleton class to the Proc class object to prevent the method cache in the interface
// impl from rooting the proc and its binding in the host classloader. See GH-4968.
((MetaClass) singletonClass).setAttached(runtime.getProc());
}

final Java.ProcToInterface procToIface = new Java.ProcToInterface(singletonClass);
singletonClass.addMethod("method_missing", procToIface);
Expand Down

0 comments on commit ef3f1e3

Please sign in to comment.