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