1 /*
2 * Copyright (c) 2012, 2016, 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 */
101 return (that instanceof LookupCase && equals((LookupCase)that));
102 }
103 public boolean equals(LookupCase that) {
104 return (this.lookupClass() == that.lookupClass() &&
105 this.lookupModes() == that.lookupModes());
106 }
107
108 @Override
109 public int hashCode() {
110 return lookupClass().hashCode() + (lookupModes() * 31);
111 }
112
113 /** Simulate all assertions in the spec. for Lookup.toString. */
114 private String lookupString() {
115 String name = lookupClass.getName();
116 String suffix = "";
117 if (lookupModes == 0)
118 suffix = "/noaccess";
119 else if (lookupModes == PUBLIC)
120 suffix = "/public";
121 else if (lookupModes == (PUBLIC|MODULE))
122 suffix = "/module";
123 else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
124 suffix = "/package";
125 else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
126 suffix = "/private";
127 else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
128 suffix = "";
129 else
130 suffix = "/#"+Integer.toHexString(lookupModes);
131 return name+suffix;
132 }
133
134 /** Simulate all assertions from the spec. for Lookup.in:
135 * <hr>
136 * Creates a lookup on the specified new lookup class.
137 * [A1] The resulting object will report the specified
138 * class as its own {@link #lookupClass lookupClass}.
139 * <p>
140 * [A2] However, the resulting {@code Lookup} object is guaranteed
141 * to have no more access capabilities than the original.
142 * In particular, access capabilities can be lost as follows:<ul>
143 * <li>[A3] If the new lookup class differs from the old one,
144 * protected members will not be accessible by virtue of inheritance.
145 * (Protected members may continue to be accessible because of package sharing.)
146 * <li>[A4] If the new lookup class is in a different package
147 * than the old one, protected and default (package) members will not be accessible.
148 * <li>[A5] If the new lookup class is not within the same package member
149 * as the old one, private members will not be accessible.
150 * <li>[A6] If the new lookup class is not accessible to the old lookup class,
151 * using the original access modes,
152 * then no members, not even public members, will be accessible.
153 * <li>[A7] If the new lookup class for this {@code Lookup} is in the unnamed module,
154 * and the new lookup class is in a named module {@code M}, then no members in
155 * {@code M}'s non-exported packages will be accessible.
156 * <li>[A8] If the lookup for this {@code Lookup} is in a named module, and the
157 * new lookup class is in a different module, then no members, not even
158 * public members in {@code M}'s exported packages, will be accessible.
159 * [A8] (In all other cases, public members will continue to be accessible.)
160 * </ul>
161 * Other than the above cases, the new lookup will have the same
162 * access capabilities as the original. [A10]
163 * <hr>
164 */
165 public LookupCase in(Class<?> c2) {
166 Class<?> c1 = lookupClass();
167 int m1 = lookupModes();
168 int changed = 0;
169 // for the purposes of access control then treat classes in different unnamed
170 // modules as being in the same module.
171 boolean sameModule = (c1.getModule() == c2.getModule()) ||
172 (!c1.getModule().isNamed() && !c2.getModule().isNamed());
173 boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
174 packagePrefix(c1).equals(packagePrefix(c2)));
175 boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
176 boolean sameClass = (c1 == c2);
177 assert(samePackage || !sameTopLevel);
178 assert(sameTopLevel || !sameClass);
179 boolean accessible = sameClass; // [A6]
180 if ((m1 & PACKAGE) != 0) accessible |= samePackage;
181 if ((m1 & PUBLIC ) != 0) accessible |= (c2.getModifiers() & PUBLIC) != 0;
182 if (!sameModule) {
183 if (c1.getModule().isNamed()) {
184 accessible = false; // [A8]
185 } else {
186 // Different module; loose MODULE and lower access.
187 changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A7]
188 }
189 }
190 if (!accessible) {
191 // Different package and no access to c2; lose all access.
192 changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A6]
193 }
194 if (!samePackage) {
195 // Different package; loose PACKAGE and lower access.
196 changed |= (PACKAGE|PRIVATE|PROTECTED); // [A4]
197 }
198 if (!sameTopLevel) {
199 // Different top-level class. Lose PRIVATE and lower access.
200 changed |= (PRIVATE|PROTECTED); // [A5]
201 }
202 if (!sameClass) {
203 changed |= (PROTECTED); // [A3]
204 } else {
205 assert(changed == 0); // [A10] (no deprivation if same class)
206 }
207 if (accessible) assert((changed & PUBLIC) == 0); // [A9]
208 int m2 = m1 & ~changed;
209 LookupCase l2 = new LookupCase(c2, m2);
210 assert(l2.lookupClass() == c2); // [A1]
211 assert((m1 | m2) == m1); // [A2] (no elevation of access)
212 return l2;
213 }
214
215 @Override
216 public String toString() {
217 String s = lookupClass().getSimpleName();
218 String lstr = lookupString();
219 int sl = lstr.indexOf('/');
220 if (sl >= 0) s += lstr.substring(sl);
221 ClassLoader cld = lookupClass().getClassLoader();
222 if (cld != THIS_LOADER) s += "/loader#"+numberOf(cld);
223 return s;
224 }
225
226 /** Predict the success or failure of accessing this method. */
227 public boolean willAccess(Method m) {
228 Class<?> c1 = lookupClass();
229 Class<?> c2 = m.getDeclaringClass();
230
231 // if the lookup class is in a loose module with PUBLIC access then
232 // public members of public types in all unnamed modules can be accessed
233 if (isLooseModule(c1.getModule())
234 && (lookupModes & PUBLIC) != 0
235 && (!c2.getModule().isNamed())
236 && Modifier.isPublic(c2.getModifiers())
237 && Modifier.isPublic(m.getModifiers()))
238 return true;
239
240 LookupCase lc = this.in(c2);
241 int m1 = lc.lookupModes();
242 int m2 = fixMods(m.getModifiers());
243 // privacy is strictly enforced on lookups
244 if (c1 != c2) m1 &= ~PRIVATE;
245 // protected access is sometimes allowed
246 if ((m2 & PROTECTED) != 0) {
247 int prev = m2;
248 m2 |= PACKAGE; // it acts like a package method also
249 if ((lookupModes() & PROTECTED) != 0 &&
250 c2.isAssignableFrom(c1))
251 m2 |= PUBLIC; // from a subclass, it acts like a public method also
252 }
253 if (verbosity >= 2)
254 System.out.println(this+" willAccess "+lc+" m1="+m1+" m2="+m2+" => "+((m2 & m1) != 0));
255 return (m2 & m1) != 0;
256 }
257
258 /** Predict the success or failure of accessing this class. */
259 public boolean willAccessClass(Class<?> c2, boolean load) {
260 Class<?> c1 = lookupClass();
261 if (load && c2.getClassLoader() != null) {
262 if (c1.getClassLoader() == null) {
263 // not visible
264 return false;
265 }
266 if (c1 == publicLookup().lookupClass()) {
267 // not visible as lookup class is defined by child of the boot loader
268 return false;
269 }
270 }
271
272 // if the lookup class is in a loose module with PUBLIC access then
273 // public types in all unnamed modules can be accessed
274 if (isLooseModule(c1.getModule())
275 && (lookupModes & PUBLIC) != 0
276 && (!c2.getModule().isNamed())
277 && Modifier.isPublic(c2.getModifiers()))
278 return true;
279
280 LookupCase lc = this.in(c2);
281 int m1 = lc.lookupModes();
282 boolean r = false;
283 if (m1 == 0) {
284 r = false;
285 } else {
286 int m2 = fixMods(c2.getModifiers());
287 if ((m2 & PUBLIC) != 0) {
288 r = true;
289 } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {
290 r = true;
291 }
292 }
293 if (verbosity >= 2) {
294 System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
295 }
296 return r;
297 }
298
299 private boolean isLooseModule(Module m) {
300 ClassLoader cl = new ClassLoader() { };
301 return m.canRead(cl.getUnnamedModule());
302 }
303 }
304
305 private static Class<?> topLevelClass(Class<?> cls) {
306 Class<?> c = cls;
307 for (Class<?> ec; (ec = c.getEnclosingClass()) != null; )
308 c = ec;
309 assert(c.getEnclosingClass() == null);
310 assert(c == cls || cls.getEnclosingClass() != null);
311 return c;
312 }
313
314 private static String packagePrefix(Class<?> c) {
315 while (c.isArray()) c = c.getComponentType();
316 String s = c.getName();
317 assert(s.indexOf('/') < 0);
318 return s.substring(0, s.lastIndexOf('.')+1);
319 }
320
321
322 private final TreeSet<LookupCase> CASES = new TreeSet<>();
323 private final TreeMap<LookupCase,TreeSet<LookupCase>> CASE_EDGES = new TreeMap<>();
324 private final ArrayList<ClassLoader> LOADERS = new ArrayList<>();
325 private final ClassLoader THIS_LOADER = this.getClass().getClassLoader();
326 { if (THIS_LOADER != null) LOADERS.add(THIS_LOADER); } // #1
327
328 private LookupCase lookupCase(String name) {
329 for (LookupCase lc : CASES) {
330 if (lc.toString().equals(name))
331 return lc;
332 }
333 throw new AssertionError(name);
334 }
335
336 private int numberOf(ClassLoader cl) {
337 if (cl == null) return 0;
338 int i = LOADERS.indexOf(cl);
339 if (i < 0) {
340 i = LOADERS.size();
341 LOADERS.add(cl);
|
1 /*
2 * Copyright (c) 2012, 2017, 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 */
101 return (that instanceof LookupCase && equals((LookupCase)that));
102 }
103 public boolean equals(LookupCase that) {
104 return (this.lookupClass() == that.lookupClass() &&
105 this.lookupModes() == that.lookupModes());
106 }
107
108 @Override
109 public int hashCode() {
110 return lookupClass().hashCode() + (lookupModes() * 31);
111 }
112
113 /** Simulate all assertions in the spec. for Lookup.toString. */
114 private String lookupString() {
115 String name = lookupClass.getName();
116 String suffix = "";
117 if (lookupModes == 0)
118 suffix = "/noaccess";
119 else if (lookupModes == PUBLIC)
120 suffix = "/public";
121 else if (lookupModes == (PUBLIC|UNCONDITIONAL))
122 suffix = "/publicLookup";
123 else if (lookupModes == (PUBLIC|MODULE))
124 suffix = "/module";
125 else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
126 suffix = "/package";
127 else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
128 suffix = "/private";
129 else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
130 suffix = "";
131 else
132 suffix = "/#"+Integer.toHexString(lookupModes);
133 return name+suffix;
134 }
135
136 /** Simulate all assertions from the spec. for Lookup.in:
137 * <hr>
138 * Creates a lookup on the specified new lookup class.
139 * [A1] The resulting object will report the specified
140 * class as its own {@link #lookupClass lookupClass}.
141 * <p>
142 * [A2] However, the resulting {@code Lookup} object is guaranteed
143 * to have no more access capabilities than the original.
144 * In particular, access capabilities can be lost as follows:<ul>
145 * <li> [A3] If the old lookup class is in a named module, and the new
146 * lookup class is in a different module {@code M}, then no members, not
147 * even public members in {@code M}'s exported packages, will be accessible.
148 * The exception to this is when this lookup is publicLookup, in which case
149 * public access is not lost.
150 * <li> [A4] If the old lookup class is in an unnamed module, and the new
151 * lookup class is a different module then module access is lost.
152 * <li> [A5] If the new lookup class differs from the old one then UNCONDITIONAL
153 * is lost. If the new lookup class is not within the same package member as the
154 * old one, protected members will not be accessible by virtue of inheritance.
155 * (Protected members may continue to be accessible because of package sharing.)
156 * <li> [A6] If the new lookup class is in a different package than the old one,
157 * protected and default (package) members will not be accessible.
158 * <li> [A7] If the new lookup class is not within the same package member
159 * as the old one, private members will not be accessible.
160 * <li> [A8] If the new lookup class is not accessible to the old lookup class,
161 * then no members, not even public members, will be accessible.
162 * <li> [A9] (In all other cases, public members will continue to be accessible.)
163 * </ul>
164 * Other than the above cases, the new lookup will have the same
165 * access capabilities as the original. [A10]
166 * <hr>
167 */
168 public LookupCase in(Class<?> c2) {
169 Class<?> c1 = lookupClass();
170 int m1 = lookupModes();
171 int changed = 0;
172 // for the purposes of access control then treat classes in different unnamed
173 // modules as being in the same module.
174 boolean sameModule = (c1.getModule() == c2.getModule()) ||
175 (!c1.getModule().isNamed() && !c2.getModule().isNamed());
176 boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
177 c1.getPackageName().equals(c2.getPackageName()));
178 boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
179 boolean sameClass = (c1 == c2);
180 assert(samePackage || !sameTopLevel);
181 assert(sameTopLevel || !sameClass);
182 boolean accessible = sameClass;
183 if ((m1 & PACKAGE) != 0) accessible |= samePackage;
184 if ((m1 & PUBLIC ) != 0) accessible |= (c2.getModifiers() & PUBLIC) != 0;
185 if (!sameModule) {
186 if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) {
187 accessible = false; // [A3]
188 } else {
189 changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A3] [A4]
190 }
191 }
192 if (!accessible) {
193 // Different package and no access to c2; lose all access.
194 changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A8]
195 }
196 if (!samePackage) {
197 // Different package; loose PACKAGE and lower access.
198 changed |= (PACKAGE|PRIVATE|PROTECTED); // [A6]
199 }
200 if (!sameTopLevel) {
201 // Different top-level class. Lose PRIVATE and PROTECTED access.
202 changed |= (PRIVATE|PROTECTED); // [A5] [A7]
203 }
204 if (!sameClass) {
205 changed |= (UNCONDITIONAL); // [A5]
206 } else {
207 assert(changed == 0); // [A10] (no deprivation if same class)
208 }
209 if (accessible) assert((changed & PUBLIC) == 0); // [A9]
210 int m2 = m1 & ~changed;
211 LookupCase l2 = new LookupCase(c2, m2);
212 assert(l2.lookupClass() == c2); // [A1]
213 assert((m1 | m2) == m1); // [A2] (no elevation of access)
214 return l2;
215 }
216
217 @Override
218 public String toString() {
219 String s = lookupClass().getSimpleName();
220 String lstr = lookupString();
221 int sl = lstr.indexOf('/');
222 if (sl >= 0) s += lstr.substring(sl);
223 ClassLoader cld = lookupClass().getClassLoader();
224 if (cld != THIS_LOADER) s += "/loader#"+numberOf(cld);
225 return s;
226 }
227
228 /** Predict the success or failure of accessing this method. */
229 public boolean willAccess(Method m) {
230 Class<?> c1 = lookupClass();
231 Class<?> c2 = m.getDeclaringClass();
232
233 // publicLookup has access to all public types/members of types in unnamed modules
234 if ((lookupModes & UNCONDITIONAL) != 0
235 && (lookupModes & PUBLIC) != 0
236 && !c2.getModule().isNamed()
237 && Modifier.isPublic(c2.getModifiers())
238 && Modifier.isPublic(m.getModifiers()))
239 return true;
240
241 LookupCase lc = this.in(c2);
242 int m1 = lc.lookupModes();
243 int m2 = fixMods(m.getModifiers());
244 // privacy is strictly enforced on lookups
245 if (c1 != c2) m1 &= ~PRIVATE;
246 // protected access is sometimes allowed
247 if ((m2 & PROTECTED) != 0) {
248 int prev = m2;
249 m2 |= PACKAGE; // it acts like a package method also
250 if ((lookupModes() & PROTECTED) != 0 &&
251 c2.isAssignableFrom(c1))
252 m2 |= PUBLIC; // from a subclass, it acts like a public method also
253 }
254 if (verbosity >= 2)
255 System.out.println(this+" willAccess "+lc+" m1="+m1+" m2="+m2+" => "+((m2 & m1) != 0));
256 return (m2 & m1) != 0;
257 }
258
259 /** Predict the success or failure of accessing this class. */
260 public boolean willAccessClass(Class<?> c2, boolean load) {
261 Class<?> c1 = lookupClass();
262 if (load && c2.getClassLoader() != null) {
263 if (c1.getClassLoader() == null) {
264 // not visible
265 return false;
266 }
267 }
268
269 // publicLookup has access to all public types/members of types in unnamed modules
270 if ((lookupModes & UNCONDITIONAL) != 0
271 && (lookupModes & PUBLIC) != 0
272 && (!c2.getModule().isNamed())
273 && Modifier.isPublic(c2.getModifiers()))
274 return true;
275
276 LookupCase lc = this.in(c2);
277 int m1 = lc.lookupModes();
278 boolean r = false;
279 if (m1 == 0) {
280 r = false;
281 } else {
282 int m2 = fixMods(c2.getModifiers());
283 if ((m2 & PUBLIC) != 0) {
284 r = true;
285 } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {
286 r = true;
287 }
288 }
289 if (verbosity >= 2) {
290 System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
291 }
292 return r;
293 }
294 }
295
296 private static Class<?> topLevelClass(Class<?> cls) {
297 Class<?> c = cls;
298 for (Class<?> ec; (ec = c.getEnclosingClass()) != null; )
299 c = ec;
300 assert(c.getEnclosingClass() == null);
301 assert(c == cls || cls.getEnclosingClass() != null);
302 return c;
303 }
304
305 private final TreeSet<LookupCase> CASES = new TreeSet<>();
306 private final TreeMap<LookupCase,TreeSet<LookupCase>> CASE_EDGES = new TreeMap<>();
307 private final ArrayList<ClassLoader> LOADERS = new ArrayList<>();
308 private final ClassLoader THIS_LOADER = this.getClass().getClassLoader();
309 { if (THIS_LOADER != null) LOADERS.add(THIS_LOADER); } // #1
310
311 private LookupCase lookupCase(String name) {
312 for (LookupCase lc : CASES) {
313 if (lc.toString().equals(name))
314 return lc;
315 }
316 throw new AssertionError(name);
317 }
318
319 private int numberOf(ClassLoader cl) {
320 if (cl == null) return 0;
321 int i = LOADERS.indexOf(cl);
322 if (i < 0) {
323 i = LOADERS.size();
324 LOADERS.add(cl);
|