From 41d784d98e8773224a03009c7375fa853caaddf9 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Wed, 18 Feb 2015 17:50:41 +0100 Subject: [PATCH] 8071657: JDI ObjectReferenceImpl.invokeMethod() validation fails for virtual invocations of method with declaring type being an interface Reviewed-by: sspitsyn, sla --- .../sun/tools/jdi/ObjectReferenceImpl.java | 14 +++++--- .../com/sun/jdi/InterfaceMethodsTest.java | 34 ++++++++++++++++--- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java index 1d5a6c909eb..f127f0c5e5d 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -282,6 +282,7 @@ public class ObjectReferenceImpl extends ValueImpl * implemented interface */ ReferenceTypeImpl declType = (ReferenceTypeImpl)method.declaringType(); + if (!declType.isAssignableFrom(this)) { throw new IllegalArgumentException("Invalid method"); } @@ -311,7 +312,7 @@ public class ObjectReferenceImpl extends ValueImpl /* * For nonvirtual invokes, method must have a body */ - if ((options & INVOKE_NONVIRTUAL) != 0) { + if (isNonVirtual(options)) { if (method.isAbstract()) { throw new IllegalArgumentException("Abstract method"); } @@ -323,7 +324,7 @@ public class ObjectReferenceImpl extends ValueImpl * method argument types. */ ClassTypeImpl invokedClass; - if ((options & INVOKE_NONVIRTUAL) != 0) { + if (isNonVirtual(options)) { // No overrides in non-virtual invokes invokedClass = clazz; } else { @@ -348,7 +349,7 @@ public class ObjectReferenceImpl extends ValueImpl /* * Only default methods allowed for nonvirtual invokes */ - if (!method.isDefault()) { + if (isNonVirtual(options) && !method.isDefault()) { throw new IllegalArgumentException("Not a default method"); } } @@ -383,6 +384,7 @@ public class ObjectReferenceImpl extends ValueImpl IncompatibleThreadStateException, InvocationException, ClassNotLoadedException { + validateMirror(threadIntf); validateMirror(methodIntf); validateMirrorsOrNulls(origArguments); @@ -624,4 +626,8 @@ public class ObjectReferenceImpl extends ValueImpl byte typeValueKey() { return JDWP.Tag.OBJECT; } + + private static boolean isNonVirtual(int options) { + return (options & INVOKE_NONVIRTUAL) != 0; + } } diff --git a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java index ef0b141fb9d..80a6b30245d 100644 --- a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java +++ b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /** * @test * @bug 8031195 + * @bug 8071657 * @summary JDI: Add support for static and default methods in interfaces * * @run build TestScaffold VMConnection TargetListener TargetAdapter @@ -38,6 +39,7 @@ public class InterfaceMethodsTest extends TestScaffold { private static final int RESULT_A = 1; private static final int RESULT_B = 1; private static final int RESULT_TARGET = 1; + static interface InterfaceA { static int staticMethodA() { System.out.println("-InterfaceA: static interface method A-"); @@ -202,6 +204,9 @@ public class InterfaceMethodsTest extends TestScaffold { // try to invoke static method B on the instance testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A)); + + // try to invoke a virtual method + testInvokePos(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(RESULT_A), true); } private void testInterfaceB(ObjectReference ref) { @@ -302,9 +307,14 @@ public class InterfaceMethodsTest extends TestScaffold { private void testInvokePos(ReferenceType targetClass, ObjectReference ref, String methodName, String methodSig, Value value) { + testInvokePos(targetClass, ref, methodName, methodSig, value, false); + } + + private void testInvokePos(ReferenceType targetClass, ObjectReference ref, String methodName, + String methodSig, Value value, boolean virtual) { logInvocation(ref, methodName, methodSig, targetClass); try { - invoke(targetClass, ref, methodName, methodSig, value); + invoke(targetClass, ref, methodName, methodSig, value, virtual); System.err.println("--- PASSED"); } catch (Exception e) { System.err.println("--- FAILED"); @@ -314,9 +324,14 @@ public class InterfaceMethodsTest extends TestScaffold { private void testInvokeNeg(ReferenceType targetClass, ObjectReference ref, String methodName, String methodSig, Value value, String msg) { + testInvokeNeg(targetClass, ref, methodName, methodSig, value, msg, false); + } + + private void testInvokeNeg(ReferenceType targetClass, ObjectReference ref, String methodName, + String methodSig, Value value, String msg, boolean virtual) { logInvocation(ref, methodName, methodSig, targetClass); try { - invoke(targetClass, ref, methodName, methodSig, value); + invoke(targetClass, ref, methodName, methodSig, value, virtual); System.err.println("--- FAILED"); failure("FAILED: " + msg); } catch (Exception e) { @@ -326,7 +341,7 @@ public class InterfaceMethodsTest extends TestScaffold { } private void invoke(ReferenceType targetClass, ObjectReference ref, String methodName, - String methodSig, Value value) + String methodSig, Value value, boolean virtual) throws Exception { Method method = getMethod(targetClass, methodName, methodSig); if (method == null) { @@ -334,10 +349,15 @@ public class InterfaceMethodsTest extends TestScaffold { } println("Invoking " + (method.isAbstract() ? "abstract " : " ") + "method: " + method); + println(method.declaringType().toString()); Value returnValue = null; if (ref != null) { - returnValue = invokeInstance(ref, method); + if (virtual) { + returnValue = invokeVirtual(ref, method); + } else { + returnValue = invokeInstance(ref, method); + } } else { returnValue = invokeStatic(targetClass, method); } @@ -362,6 +382,10 @@ public class InterfaceMethodsTest extends TestScaffold { return ref.invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL); } + private Value invokeVirtual(ObjectReference ref, Method method) throws Exception { + return ref.invokeMethod(mainThread, method, Collections.emptyList(), 0); + } + private Value invokeStatic(ReferenceType refType, Method method) throws Exception { if (refType instanceof ClassType) { return ((ClassType)refType).invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL);