|
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 } |