1 /* 2 * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package invokevirtual; 26 27 import java.lang.reflect.Method; 28 import java.lang.reflect.Modifier; 29 30 31 public class Checker extends shared.Checker { 32 public Checker(Class staticTargetClass, Class dynamicTargetClass) { 33 super(staticTargetClass, dynamicTargetClass); 34 } 35 36 public String check (Class callerClass) { 37 Method m; 38 try { 39 // May cause java.lang.VerifyError 40 m = getOverriddenMethod(); 41 } catch (Throwable e) { 42 return e.getClass().getName(); 43 } 44 45 // Check method accessibility (it's a static property, according to JLS #6.6: Access Control) 46 if (m != null) { 47 Method staticTargetMethod = getDeclaredMethod(staticTargetClass); 48 49 if (checkAccess(staticTargetMethod, callerClass)) { 50 // Can't invoke abstract method 51 if ( Modifier.isAbstract(m.getModifiers())) { 52 return "java.lang.AbstractMethodError"; 53 } 54 55 return String.format("%s.%s" 56 , m.getDeclaringClass().getSimpleName() 57 , methodName 58 ); 59 } else { 60 // if method isn't accessible, IllegalAccessError is thrown 61 return "java.lang.IllegalAccessError"; 62 } 63 } else { 64 // if method == null, NoSuchMethodError is thrown 65 return "java.lang.NoSuchMethodError"; 66 } 67 } 68 69 public Method getOverriddenMethod() { 70 return getOverriddenMethod(staticTargetClass, dynamicTargetClass); 71 } 72 73 public Method getOverriddenMethod(Class staticTarget, Class dynamicTarget) { 74 // Assertion #1. C is a subclass of A 75 if (!staticTarget.isAssignableFrom(dynamicTarget)) { 76 return null; 77 } 78 79 Method staticTargetMethod = getDeclaredMethod(staticTarget); 80 Method dynamicTargetMethod = getDeclaredMethod(dynamicTarget); 81 82 if (staticTarget.equals(dynamicTarget)) { 83 return staticTargetMethod; 84 } 85 86 // TODO: ? need to find out the right behavior 87 if (staticTargetMethod == null) { 88 return null; 89 } 90 91 // Dynamic target doesn't have desired method, so check it's superclass 92 if (dynamicTargetMethod == null) { 93 return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass()); 94 } else { 95 // Private method can't override anything 96 if (Modifier.isPrivate(dynamicTargetMethod.getModifiers())) { 97 return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass()); 98 } 99 } 100 101 // TODO: abstract methods 102 103 //Assertion #3.a: A.m2 is PUB || PROT || (PP && PKG(A) == PKG(C)) 104 int staticTargetModifiers = staticTargetMethod.getModifiers(); 105 { 106 boolean isPublic = Modifier.isPublic(staticTargetModifiers); 107 boolean isProtected = Modifier.isProtected(staticTargetModifiers); 108 boolean isPrivate = Modifier.isPrivate(staticTargetModifiers) ; 109 String staticTargetPkg = getClassPackageName(staticTarget); 110 String dynamicTargetPkg = getClassPackageName(dynamicTarget); 111 112 if ( isPublic || isProtected 113 || ( !isPublic && !isProtected && !isPrivate 114 && staticTargetPkg.equals(dynamicTargetPkg) 115 )) 116 { 117 return dynamicTargetMethod; 118 } 119 } 120 // OR 121 //Assertion #3.b: exists m3: C.m1 != B.m3, A.m2 != B.m3, B.m3 overrides A.m2, C.m1 overrides B.m3 122 Class ancestor = dynamicTarget.getSuperclass(); 123 while (ancestor != staticTarget) { 124 Method OverriddenM2 = getOverriddenMethod(staticTarget, ancestor); 125 Method m3 = getDeclaredMethod(ancestor); 126 Method m1 = getOverriddenMethod(ancestor, dynamicTarget); 127 128 if (m1 != null && m3 != null) { 129 if (m1.equals(dynamicTargetMethod) && m3.equals(OverriddenM2)) { 130 return dynamicTargetMethod; 131 } 132 } else { 133 if (m1 == null && dynamicTargetMethod == null 134 && m3 == null && OverriddenM2 == null) 135 { 136 return null; 137 } 138 } 139 140 ancestor = ancestor.getSuperclass(); 141 } 142 143 return getOverriddenMethod(staticTarget, dynamicTarget.getSuperclass()); 144 } 145 }