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 invokespecial; 26 27 import java.lang.reflect.Method; 28 import java.lang.reflect.Modifier; 29 30 public class Checker extends shared.Checker { 31 32 public Checker(Class staticTargetClass, Class dynamicTargetClass) { 33 super(staticTargetClass, dynamicTargetClass); 34 } 35 36 public String check (Class callerClass) { 37 /* 38 * If objectref is null, the invokespecial instruction throws a NullPointerException. 39 */ 40 if (dynamicTargetClass == null) { 41 return "java.lang.NullPointerException"; 42 } 43 44 /* 45 * TODO: find a citiation from spec for this case 46 */ 47 Method resolvedMethod; 48 try { 49 // May throw VerifyError 50 resolvedMethod = getMethodInHierarchy(staticTargetClass); 51 } catch (Throwable e) { 52 return e.getClass().getName(); 53 } 54 55 if (resolvedMethod == null) { 56 return "java.lang.NoSuchMethodError"; 57 } 58 59 /* 60 * If: 61 * - the resolved method is protected (4.7) 62 * - it is a member of a superclass of the current class 63 * - the method is not declared in the same run-time package (5.3) as the current class 64 * then: 65 * the class of objectref must be either the current class or a subclass of the 66 * current class. 67 */ 68 69 if (Modifier.isProtected(resolvedMethod.getModifiers())) { 70 Method methodInSuperclass = getMethodInHierarchy(resolvedMethod.getDeclaringClass().getSuperclass()); 71 72 if (methodInSuperclass != null) { 73 String resolvedMethodPkg = getClassPackageName(resolvedMethod.getDeclaringClass()); 74 String methodInSuperclassPkg = getClassPackageName(methodInSuperclass.getDeclaringClass()); 75 76 if (!resolvedMethodPkg.equals(methodInSuperclassPkg)) { 77 //TODO: clarify this 78 // if (callerClass == methodInSuperclass.getDeclaringClass()) { 79 // return "java.lang.IllegalAccessError"; 80 // } 81 } 82 } 83 } 84 85 /* 86 * The resolved method is selected for invocation unless all of 87 * the following conditions are true: 88 * * TODO: The ACC_SUPER flag (see Table 4.1, "Class access and property 89 * modifiers") is set for the current class. 90 * * The class of the resolved method is a superclass of the 91 * current class - assumed by construction procedure 92 * 93 * * The resolved method is not an instance initialization method (3.9). 94 */ 95 if (!"<init>".equals(methodName)) { 96 /* 97 * Let C be the direct superclass of the current class: 98 * * If C contains a declaration for an instance method with the same 99 * name and descriptor as the resolved method, then this method will be 100 * invoked. The lookup procedure terminates. 101 * * Otherwise, if C has a superclass, this same lookup procedure is 102 * performed recursively using the direct superclass of C. The method to 103 * be invoked is the result of the recursive invocation of this lookup 104 * procedure. 105 * * Otherwise, an AbstractMethodError is raised. 106 * TODO: so far, sometimes NSME is thrown 107 */ 108 Class klass = dynamicTargetClass.getSuperclass(); 109 110 while (klass != Object.class) { 111 Method method = getDeclaredMethod(klass); 112 113 if (method != null) { 114 /* 115 * If the resolved method is a class (static) method, the 116 * invokespecial instruction throws an IncompatibleClassChangeError. 117 */ 118 if (Modifier.isStatic(method.getModifiers())) { 119 return "java.lang.IncompatibleClassChangeError"; 120 } 121 122 // Check access rights 123 if ( checkAccess(method, callerClass) 124 // && !( 125 // Modifier.isProtected(method.getModifiers()) 126 // && ( 127 // staticTargetClass.isAssignableFrom(callerClass) 128 // || getClassPackageName(staticTargetClass).equals(getClassPackageName(callerClass)) 129 // ) 130 // 131 // ) 132 ) 133 { 134 return String.format("%s.%s" 135 , method.getDeclaringClass().getSimpleName() 136 , methodName 137 ); 138 } else { 139 // IAE is thrown when located method can't be accessed from the call site 140 return "java.lang.IllegalAccessError"; 141 } 142 } 143 144 klass = klass.getSuperclass(); 145 } 146 147 return "java.lang.AbstractMethodError"; 148 } else { 149 // The resolved method is an instance initialization method (3.9). 150 } 151 152 // TODO: change 153 return "---"; 154 } 155 }