From 62a06c587c3236576fa298d097d924982cdc6af9 Mon Sep 17 00:00:00 2001 From: Greg Bowyer Date: Thu, 25 Aug 2016 16:26:58 -0700 Subject: [PATCH 1/2] Attempted fix for bridges that are created to do Object -> Type --- .../sf/cglib/proxy/BridgeMethodResolver.java | 9 +++- .../java/net/sf/cglib/proxy/Enhancer.java | 29 ++++++++++++ .../java/net/sf/cglib/proxy/TestEnhancer.java | 47 ++++++++++++++++++- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/cglib/src/main/java/net/sf/cglib/proxy/BridgeMethodResolver.java b/cglib/src/main/java/net/sf/cglib/proxy/BridgeMethodResolver.java index 574857c1..7e4c34fd 100644 --- a/cglib/src/main/java/net/sf/cglib/proxy/BridgeMethodResolver.java +++ b/cglib/src/main/java/net/sf/cglib/proxy/BridgeMethodResolver.java @@ -59,7 +59,7 @@ public BridgeMethodResolver(Map declToBridge) { Set bridges = (Set)entry.getValue(); try { new ClassReader(owner.getName()) - .accept(new BridgedFinder(bridges, resolved), + .accept(new BridgedFinder(bridges, resolved, owner.getName()), ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); } catch(IOException ignored) {} } @@ -71,11 +71,13 @@ private static class BridgedFinder extends ClassVisitor { private Set/**/ eligableMethods; private Signature currentMethod = null; + private String name; - BridgedFinder(Set eligableMethods, Map resolved) { + BridgedFinder(Set eligableMethods, Map resolved, String name) { super(Opcodes.ASM5); this.resolved = resolved; this.eligableMethods = eligableMethods; + this.name = name; } public void visit(int version, int access, String name, @@ -85,11 +87,14 @@ public void visit(int version, int access, String name, public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { Signature sig = new Signature(name, desc); + + final String selfName = this.name; if (eligableMethods.remove(sig)) { currentMethod = sig; return new MethodVisitor(Opcodes.ASM5) { public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (opcode == Opcodes.INVOKESPECIAL && currentMethod != null) { Signature target = new Signature(name, desc); // If the target signature is the same as the current, diff --git a/cglib/src/main/java/net/sf/cglib/proxy/Enhancer.java b/cglib/src/main/java/net/sf/cglib/proxy/Enhancer.java index 7e7d831b..44b8336d 100644 --- a/cglib/src/main/java/net/sf/cglib/proxy/Enhancer.java +++ b/cglib/src/main/java/net/sf/cglib/proxy/Enhancer.java @@ -1162,6 +1162,35 @@ public void emitInvoke(CodeEmitter e, MethodInfo method) { // any proxies on the target. Signature bridgeTarget = (Signature)bridgeToTarget.get(method.getSignature()); if (bridgeTarget != null) { + Type[] argumentTypes = method.getSignature().getArgumentTypes(); + Type[] bridgeTypes = bridgeTarget.getArgumentTypes(); + + // This should never happen, but its a simple check + if (argumentTypes.length != bridgeTarget.getArgumentTypes().length) { + throw new IllegalStateException("Mismatched method signatures?"); + } + + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + + try { + for (int i = 0; i < argumentTypes.length; i++) { + Type argType = argumentTypes[i]; + Type targetType = bridgeTypes[i]; + // This should be a fast check + if (!argType.getClassName().equals(targetType.getClassName())) { + Class argClass = loader.loadClass(argType.getClassName()); + Class targetClass = loader.loadClass(targetType.getClassName()); + + if (argClass == Object.class && targetClass != Object.class) { + e.super_invoke(method.getSignature()); + return; + } + } + } + } catch (ClassNotFoundException ignored) { + e.super_invoke(method.getSignature()); + } + // TODO: this assumes that the target has wider or the same type // parameters than the current. // In reality this should always be true because otherwise we wouldn't diff --git a/cglib/src/test/java/net/sf/cglib/proxy/TestEnhancer.java b/cglib/src/test/java/net/sf/cglib/proxy/TestEnhancer.java index 03a7db1f..bf0d0cf7 100644 --- a/cglib/src/test/java/net/sf/cglib/proxy/TestEnhancer.java +++ b/cglib/src/test/java/net/sf/cglib/proxy/TestEnhancer.java @@ -1174,7 +1174,38 @@ public int accept(Method method) { intf.widenReturn(null); assertEquals(Arrays.asList(RetType.class, ErasedType.class), paramTypes); } - + + public void testBridgesTypeErasedFromChildToParent() { + List retTypes = new ArrayList(); + List paramTypes = new ArrayList(); + Interceptor interceptor = new Interceptor(retTypes, paramTypes); + + Enhancer e = new Enhancer(); + e.setSuperclass(OtherImpl.class); + e.setCallbackFilter(new CallbackFilter() { + public int accept(Method method) { + return method.getDeclaringClass() != Object.class ? 0 : 1; + } + }); + e.setCallbacks(new Callback[] { interceptor, NoOp.INSTANCE }); + // We expect the bridge ('ret') to be called & forward us to the non-bridge 'erased' + ParameterisedInterfaceNotTypeBounded intf = + (ParameterisedInterfaceNotTypeBounded) e.create(); + intf.aMethod(new Refined()); + // There is no actual implementation of aMethod in the subclass, however it has a bridge going + // Object -> superclass with a cast + assertEquals(Arrays.asList(Object.class), retTypes); + + // The bridge internally emits a checkclass, if it does not cglib should emit this. + boolean fail = true; + try { + intf.aMethod("String"); + } catch (ClassCastException cce) { + fail = false; + } + assertFalse("Bridge did not emit checkclass instruction", fail); + } + public void testBridgeForcesInvokeVirtualEvenWithoutInterceptingBridge() { List retTypes = new ArrayList(); Interceptor interceptor = new Interceptor(retTypes); @@ -1280,11 +1311,25 @@ public interface Interface { // the usage of the interface forces the bridge // a wider type than in superclass ErasedType widenReturn(RetType obj); } + // This has a shape that fits the typing of the class heirachy, but the generic T + // is not bound to ErasedType directly. It creates bridge methods that + // given an abstract parent, will need to be ignored for creation of + // invokevirtual + public interface ParameterisedInterfaceNotTypeBounded { + T aMethod(T obj); + void voidReturn(T obj); + int intReturn(T obj); + // a wider type than in superclass + ErasedType widenReturn(T obj); + } public static class Impl extends Superclass implements Interface { // An even more narrowed type, just to make sure // it doesn't confuse us. public Refined aMethod(Refined obj) { return null; } } + public static class OtherImpl extends Superclass implements ParameterisedInterfaceNotTypeBounded { + public String irrelvantMethod() { return "Not important"; } + } // Another set of classes -- this time with the bridging in reverse, // to make sure that if we define the concrete type, a bridge From b6a7a110e86c23b93b30ca7dca3e945c3414ea77 Mon Sep 17 00:00:00 2001 From: Greg Bowyer Date: Thu, 25 Aug 2016 16:26:39 -0700 Subject: [PATCH 2/2] [NOCOMMIT] Change version for testing --- cglib-integration-test/pom.xml | 2 +- cglib-jmh/pom.xml | 2 +- cglib-nodep/pom.xml | 2 +- cglib-sample/pom.xml | 2 +- cglib/pom.xml | 2 +- pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cglib-integration-test/pom.xml b/cglib-integration-test/pom.xml index 8f978bc1..0d059b79 100644 --- a/cglib-integration-test/pom.xml +++ b/cglib-integration-test/pom.xml @@ -9,7 +9,7 @@ cglib cglib-parent - 3.2.5-SNAPSHOT + 3.2.5-GREG-SNAPSHOT diff --git a/cglib-jmh/pom.xml b/cglib-jmh/pom.xml index 2c8e3966..705e99c6 100644 --- a/cglib-jmh/pom.xml +++ b/cglib-jmh/pom.xml @@ -7,7 +7,7 @@ cglib-parent cglib - 3.2.5-SNAPSHOT + 3.2.5-GREG-SNAPSHOT 4.0.0 diff --git a/cglib-nodep/pom.xml b/cglib-nodep/pom.xml index 0cafe317..ea8182bb 100644 --- a/cglib-nodep/pom.xml +++ b/cglib-nodep/pom.xml @@ -9,7 +9,7 @@ cglib cglib-parent - 3.2.5-SNAPSHOT + 3.2.5-GREG-SNAPSHOT diff --git a/cglib-sample/pom.xml b/cglib-sample/pom.xml index e550939e..36bae1e4 100644 --- a/cglib-sample/pom.xml +++ b/cglib-sample/pom.xml @@ -9,7 +9,7 @@ cglib cglib-parent - 3.2.5-SNAPSHOT + 3.2.5-GREG-SNAPSHOT diff --git a/cglib/pom.xml b/cglib/pom.xml index 9a57985e..ef52e049 100644 --- a/cglib/pom.xml +++ b/cglib/pom.xml @@ -9,7 +9,7 @@ cglib cglib-parent - 3.2.5-SNAPSHOT + 3.2.5-GREG-SNAPSHOT diff --git a/pom.xml b/pom.xml index 70675135..3386ec9f 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ cglib cglib-parent - 3.2.5-SNAPSHOT + 3.2.5-GREG-SNAPSHOT pom Code Generation Library