< prev index next >
test/jdk/java/lang/invoke/AccessControlTest.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
--- 1,7 ----
/*
! * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*** 31,41 ****
import java.lang.invoke.*;
import java.lang.reflect.*;
import java.lang.reflect.Modifier;
import java.util.*;
- import org.testng.*;
import org.testng.annotations.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodHandles.Lookup.*;
import static java.lang.invoke.MethodType.*;
--- 31,40 ----
*** 60,109 ****
}
private class LookupCase implements Comparable<LookupCase> {
final Lookup lookup;
final Class<?> lookupClass;
final int lookupModes;
public LookupCase(Lookup lookup) {
this.lookup = lookup;
this.lookupClass = lookup.lookupClass();
this.lookupModes = lookup.lookupModes();
assert(lookupString().equals(lookup.toString()));
numberOf(lookupClass().getClassLoader()); // assign CL#
}
! public LookupCase(Class<?> lookupClass, int lookupModes) {
this.lookup = null;
this.lookupClass = lookupClass;
this.lookupModes = lookupModes;
numberOf(lookupClass().getClassLoader()); // assign CL#
}
public final Class<?> lookupClass() { return lookupClass; }
public final int lookupModes() { return lookupModes; }
public Lookup lookup() { lookup.getClass(); return lookup; }
@Override
public int compareTo(LookupCase that) {
Class<?> c1 = this.lookupClass();
Class<?> c2 = that.lookupClass();
if (c1 != c2) {
int cmp = c1.getName().compareTo(c2.getName());
if (cmp != 0) return cmp;
cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader());
assert(cmp != 0);
return cmp;
}
return -(this.lookupModes() - that.lookupModes());
}
@Override
public boolean equals(Object that) {
return (that instanceof LookupCase && equals((LookupCase)that));
}
public boolean equals(LookupCase that) {
return (this.lookupClass() == that.lookupClass() &&
this.lookupModes() == that.lookupModes());
}
@Override
public int hashCode() {
--- 59,126 ----
}
private class LookupCase implements Comparable<LookupCase> {
final Lookup lookup;
final Class<?> lookupClass;
+ final Class<?> prevLookupClass;
final int lookupModes;
public LookupCase(Lookup lookup) {
this.lookup = lookup;
this.lookupClass = lookup.lookupClass();
+ this.prevLookupClass = lookup.previousLookupClass();
this.lookupModes = lookup.lookupModes();
+
assert(lookupString().equals(lookup.toString()));
numberOf(lookupClass().getClassLoader()); // assign CL#
}
! public LookupCase(Class<?> lookupClass, Class<?> prevLookupClass, int lookupModes) {
this.lookup = null;
this.lookupClass = lookupClass;
+ this.prevLookupClass = prevLookupClass;
this.lookupModes = lookupModes;
numberOf(lookupClass().getClassLoader()); // assign CL#
}
public final Class<?> lookupClass() { return lookupClass; }
+ public final Class<?> prevLookupClass() { return prevLookupClass; }
public final int lookupModes() { return lookupModes; }
public Lookup lookup() { lookup.getClass(); return lookup; }
@Override
public int compareTo(LookupCase that) {
Class<?> c1 = this.lookupClass();
Class<?> c2 = that.lookupClass();
+ Class<?> p1 = this.prevLookupClass();
+ Class<?> p2 = that.prevLookupClass();
if (c1 != c2) {
int cmp = c1.getName().compareTo(c2.getName());
if (cmp != 0) return cmp;
cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader());
assert(cmp != 0);
return cmp;
+ } else if (p1 != p2){
+ if (p1 == null)
+ return 1;
+ else if (p2 == null)
+ return -1;
+ int cmp = p1.getName().compareTo(p2.getName());
+ if (cmp != 0) return cmp;
+ cmp = numberOf(p1.getClassLoader()) - numberOf(p2.getClassLoader());
+ assert(cmp != 0);
+ return cmp;
}
return -(this.lookupModes() - that.lookupModes());
}
@Override
public boolean equals(Object that) {
return (that instanceof LookupCase && equals((LookupCase)that));
}
public boolean equals(LookupCase that) {
return (this.lookupClass() == that.lookupClass() &&
+ this.prevLookupClass() == that.prevLookupClass() &&
this.lookupModes() == that.lookupModes());
}
@Override
public int hashCode() {
*** 111,134 ****
}
/** Simulate all assertions in the spec. for Lookup.toString. */
private String lookupString() {
String name = lookupClass.getName();
String suffix = "";
if (lookupModes == 0)
suffix = "/noaccess";
else if (lookupModes == PUBLIC)
suffix = "/public";
! else if (lookupModes == (PUBLIC|UNCONDITIONAL))
suffix = "/publicLookup";
else if (lookupModes == (PUBLIC|MODULE))
suffix = "/module";
! else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
suffix = "/package";
! else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
suffix = "/private";
! else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
suffix = "";
else
suffix = "/#"+Integer.toHexString(lookupModes);
return name+suffix;
}
--- 128,156 ----
}
/** Simulate all assertions in the spec. for Lookup.toString. */
private String lookupString() {
String name = lookupClass.getName();
+ if (prevLookupClass != null)
+ name += "/" + prevLookupClass.getName();
String suffix = "";
if (lookupModes == 0)
suffix = "/noaccess";
else if (lookupModes == PUBLIC)
suffix = "/public";
! else if (lookupModes == UNCONDITIONAL)
suffix = "/publicLookup";
else if (lookupModes == (PUBLIC|MODULE))
suffix = "/module";
! else if (lookupModes == (PUBLIC|PACKAGE)
! || lookupModes == (PUBLIC|MODULE|PACKAGE))
suffix = "/package";
! else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE)
! || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
suffix = "/private";
! else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED)
! || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
suffix = "";
else
suffix = "/#"+Integer.toHexString(lookupModes);
return name+suffix;
}
*** 136,221 ****
/** Simulate all assertions from the spec. for Lookup.in:
* <hr>
* Creates a lookup on the specified new lookup class.
* [A1] The resulting object will report the specified
* class as its own {@link #lookupClass lookupClass}.
- * <p>
* [A2] However, the resulting {@code Lookup} object is guaranteed
* to have no more access capabilities than the original.
* In particular, access capabilities can be lost as follows:<ul>
! * <li> [A3] If the old lookup class is in a named module, and the new
! * lookup class is in a different module {@code M}, then no members, not
! * even public members in {@code M}'s exported packages, will be accessible.
! * The exception to this is when this lookup is publicLookup, in which case
! * public access is not lost.
! * <li> [A4] If the old lookup class is in an unnamed module, and the new
! * lookup class is a different module then module access is lost.
! * <li> [A5] If the new lookup class differs from the old one then UNCONDITIONAL
! * is lost. If the new lookup class is not within the same package member as the
! * old one, protected members will not be accessible by virtue of inheritance.
* (Protected members may continue to be accessible because of package sharing.)
! * <li> [A6] If the new lookup class is in a different package than the old one,
! * protected and default (package) members will not be accessible.
! * <li> [A7] If the new lookup class is not within the same package member
! * as the old one, private members will not be accessible.
! * <li> [A8] If the new lookup class is not accessible to the old lookup class,
! * then no members, not even public members, will be accessible.
! * <li> [A9] (In all other cases, public members will continue to be accessible.)
! * </ul>
* Other than the above cases, the new lookup will have the same
! * access capabilities as the original. [A10]
* <hr>
*/
public LookupCase in(Class<?> c2) {
Class<?> c1 = lookupClass();
! int m1 = lookupModes();
int changed = 0;
// for the purposes of access control then treat classes in different unnamed
// modules as being in the same module.
! boolean sameModule = (c1.getModule() == c2.getModule()) ||
! (!c1.getModule().isNamed() && !c2.getModule().isNamed());
boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
c1.getPackageName().equals(c2.getPackageName()));
boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
boolean sameClass = (c1 == c2);
assert(samePackage || !sameTopLevel);
assert(sameTopLevel || !sameClass);
boolean accessible = sameClass;
! if ((m1 & PACKAGE) != 0) accessible |= samePackage;
! if ((m1 & PUBLIC ) != 0) accessible |= (c2.getModifiers() & PUBLIC) != 0;
! if (!sameModule) {
! if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) {
! accessible = false; // [A3]
! } else {
! changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A3] [A4]
}
}
if (!accessible) {
! // Different package and no access to c2; lose all access.
! changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A8]
}
if (!samePackage) {
// Different package; loose PACKAGE and lower access.
! changed |= (PACKAGE|PRIVATE|PROTECTED); // [A6]
}
if (!sameTopLevel) {
// Different top-level class. Lose PRIVATE and PROTECTED access.
! changed |= (PRIVATE|PROTECTED); // [A5] [A7]
}
! if (!sameClass) {
! changed |= (UNCONDITIONAL); // [A5]
! } else {
! assert(changed == 0); // [A10] (no deprivation if same class)
}
! if (accessible) assert((changed & PUBLIC) == 0); // [A9]
! int m2 = m1 & ~changed;
! LookupCase l2 = new LookupCase(c2, m2);
assert(l2.lookupClass() == c2); // [A1]
! assert((m1 | m2) == m1); // [A2] (no elevation of access)
return l2;
}
@Override
public String toString() {
String s = lookupClass().getSimpleName();
String lstr = lookupString();
int sl = lstr.indexOf('/');
--- 158,297 ----
/** Simulate all assertions from the spec. for Lookup.in:
* <hr>
* Creates a lookup on the specified new lookup class.
* [A1] The resulting object will report the specified
* class as its own {@link #lookupClass lookupClass}.
* [A2] However, the resulting {@code Lookup} object is guaranteed
* to have no more access capabilities than the original.
* In particular, access capabilities can be lost as follows:<ul>
! * [A3] If the new lookup class is in a different module from the old one,
! * i.e. {@link #MODULE MODULE} access is lost.
! * [A4] If the new lookup class is in a different package
! * than the old one, protected and default (package) members will not be accessible,
! * i.e. {@link #PROTECTED PROTECTED} and {@link #PACKAGE PACKAGE} access are lost.
! * [A5] If the new lookup class is not within the same package member
! * as the old one, private members will not be accessible, and protected members
! * will not be accessible by virtue of inheritance,
! * i.e. {@link #PRIVATE PRIVATE} access is lost.
* (Protected members may continue to be accessible because of package sharing.)
! * [A6] If the new lookup class is not
! * {@linkplain #accessClass(Class) accessible} to this lookup,
! * then no members, not even public members, will be accessible
! * i.e. all access modes are lost.
! * [A7] If the new lookup class, the old lookup class and the previous lookup class
! * are all in different modules i.e. teleporting to a third module,
! * all access modes are lost.
! * <p>
! * The new previous lookup class is chosen as follows:
! * [A8] If the new lookup object has {@link #UNCONDITIONAL UNCONDITIONAL} bit,
! * the new previous lookup class is {@code null}.
! * [A9] If the new lookup class is in the same module as the old lookup class,
! * the new previous lookup class is the old previous lookup class.
! * [A10] If the new lookup class is in a different module from the old lookup class,
! * the new previous lookup class is the the old lookup class.
! *
* Other than the above cases, the new lookup will have the same
! * access capabilities as the original. [A11]
* <hr>
*/
public LookupCase in(Class<?> c2) {
Class<?> c1 = lookupClass();
! Module m1 = c1.getModule();
! Module m2 = c2.getModule();
! Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : c1.getModule();
! int modes1 = lookupModes();
int changed = 0;
// for the purposes of access control then treat classes in different unnamed
// modules as being in the same module.
! boolean sameModule = (m1 == m2) ||
! (!m1.isNamed() && !m2.isNamed());
boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
c1.getPackageName().equals(c2.getPackageName()));
boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
boolean sameClass = (c1 == c2);
assert(samePackage || !sameTopLevel);
assert(sameTopLevel || !sameClass);
boolean accessible = sameClass;
!
! if ((modes1 & PACKAGE) != 0) accessible |= samePackage;
! if ((modes1 & PUBLIC ) != 0) {
! if (isModuleAccessible(c2))
! accessible |= (c2.getModifiers() & PUBLIC) != 0;
! else
! accessible = false;
}
+ if ((modes1 & UNCONDITIONAL) != 0) {
+ if (m2.isExported(c2.getPackageName()))
+ accessible |= (c2.getModifiers() & PUBLIC) != 0;
+ else
+ accessible = false;
}
if (!accessible) {
! // no access to c2; lose all access.
! changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED|UNCONDITIONAL); // [A6]
! }
! if (m2 != m1 && m0 != m1) {
! // hop to a third module; lose all access
! changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A7]
! }
! if (!sameModule) {
! changed |= MODULE; // [A3]
}
if (!samePackage) {
// Different package; loose PACKAGE and lower access.
! changed |= (PACKAGE|PRIVATE|PROTECTED); // [A4]
}
if (!sameTopLevel) {
// Different top-level class. Lose PRIVATE and PROTECTED access.
! changed |= (PRIVATE|PROTECTED); // [A5]
}
! if (sameClass) {
! assert(changed == 0); // [A11] (no deprivation if same class)
}
!
! if (accessible) assert((changed & PUBLIC) == 0);
! int modes2 = modes1 & ~changed;
! Class<?> plc = (m1 == m2) ? prevLookupClass() : c1; // [A9] [A10]
! if ((modes1 & UNCONDITIONAL) != 0) plc = null; // [A8]
! LookupCase l2 = new LookupCase(c2, plc, modes2);
assert(l2.lookupClass() == c2); // [A1]
! assert((modes1 | modes2) == modes1); // [A2] (no elevation of access)
! assert(l2.prevLookupClass() == null || (modes2 & MODULE) == 0);
return l2;
}
+ LookupCase dropLookupMode(int modeToDrop) {
+ int oldModes = lookupModes();
+ int newModes = oldModes & ~(modeToDrop | PROTECTED);
+ switch (modeToDrop) {
+ case PUBLIC: newModes &= ~(MODULE|PACKAGE|PROTECTED|PRIVATE); break;
+ case MODULE: newModes &= ~(PACKAGE|PRIVATE); break;
+ case PACKAGE: newModes &= ~(PRIVATE); break;
+ case PROTECTED:
+ case PRIVATE:
+ case UNCONDITIONAL: break;
+ default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
+ }
+ if (newModes == oldModes) return this; // return self if no change
+ LookupCase l2 = new LookupCase(lookupClass(), prevLookupClass(), newModes);
+ assert((oldModes | newModes) == oldModes); // [A2] (no elevation of access)
+ assert(l2.prevLookupClass() == null || (newModes & MODULE) == 0);
+ return l2;
+ }
+
+ boolean isModuleAccessible(Class<?> c) {
+ Module m1 = lookupClass().getModule();
+ Module m2 = c.getModule();
+ Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : m1;
+ String pn = c.getPackageName();
+ boolean accessible = m1.canRead(m2) && m2.isExported(pn, m1);
+ if (m1 != m0) {
+ accessible = accessible && m0.canRead(m2) && m2.isExported(pn, m0);
+ }
+ return accessible;
+ }
+
@Override
public String toString() {
String s = lookupClass().getSimpleName();
String lstr = lookupString();
int sl = lstr.indexOf('/');
*** 227,263 ****
/** Predict the success or failure of accessing this method. */
public boolean willAccess(Method m) {
Class<?> c1 = lookupClass();
Class<?> c2 = m.getDeclaringClass();
! // publicLookup has access to all public types/members of types in unnamed modules
! if ((lookupModes & UNCONDITIONAL) != 0
! && (lookupModes & PUBLIC) != 0
! && !c2.getModule().isNamed()
&& Modifier.isPublic(c2.getModifiers())
! && Modifier.isPublic(m.getModifiers()))
! return true;
LookupCase lc = this.in(c2);
! int m1 = lc.lookupModes();
! int m2 = fixMods(m.getModifiers());
// allow private lookup on nestmates. Otherwise, privacy is strictly enforced
! if (c1 != c2 && ((m2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
! m1 &= ~PRIVATE;
}
// protected access is sometimes allowed
! if ((m2 & PROTECTED) != 0) {
! int prev = m2;
! m2 |= PACKAGE; // it acts like a package method also
if ((lookupModes() & PROTECTED) != 0 &&
c2.isAssignableFrom(c1))
! m2 |= PUBLIC; // from a subclass, it acts like a public method also
}
if (verbosity >= 2)
! System.out.format("%s willAccess %s m1=0x%h m2=0x%h => %s%n", this, lc, m1, m2, ((m2 & m1) != 0));
! return (m2 & m1) != 0;
}
/** Predict the success or failure of accessing this class. */
public boolean willAccessClass(Class<?> c2, boolean load) {
Class<?> c1 = lookupClass();
--- 303,354 ----
/** Predict the success or failure of accessing this method. */
public boolean willAccess(Method m) {
Class<?> c1 = lookupClass();
Class<?> c2 = m.getDeclaringClass();
+ Module m1 = c1.getModule();
+ Module m2 = c2.getModule();
+ Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1;
+ // unconditional has access to all public types/members of types that is in a package
+ // are unconditionally exported
+ if ((lookupModes & UNCONDITIONAL) != 0) {
+ return m2.isExported(c2.getPackageName())
+ && Modifier.isPublic(c2.getModifiers())
+ && Modifier.isPublic(m.getModifiers());
+ }
! // c1 and c2 are in different module
! if (m1 != m2 || m0 != m2) {
! return (lookupModes & PUBLIC) != 0
! && isModuleAccessible(c2)
&& Modifier.isPublic(c2.getModifiers())
! && Modifier.isPublic(m.getModifiers());
! }
!
! assert(m1 == m2 && prevLookupClass == null);
!
! if (!willAccessClass(c2, false))
! return false;
LookupCase lc = this.in(c2);
! int modes1 = lc.lookupModes();
! int modes2 = fixMods(m.getModifiers());
// allow private lookup on nestmates. Otherwise, privacy is strictly enforced
! if (c1 != c2 && ((modes2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
! modes1 &= ~PRIVATE;
}
// protected access is sometimes allowed
! if ((modes2 & PROTECTED) != 0) {
! int prev = modes2;
! modes2 |= PACKAGE; // it acts like a package method also
if ((lookupModes() & PROTECTED) != 0 &&
c2.isAssignableFrom(c1))
! modes2 |= PUBLIC; // from a subclass, it acts like a public method also
}
if (verbosity >= 2)
! System.out.format("%s willAccess %s modes1=0x%h modes2=0x%h => %s%n", lookupString(), lc.lookupString(), modes1, modes2, (modes2 & modes1) != 0);
! return (modes2 & modes1) != 0;
}
/** Predict the success or failure of accessing this class. */
public boolean willAccessClass(Class<?> c2, boolean load) {
Class<?> c1 = lookupClass();
*** 266,292 ****
// not visible
return false;
}
}
! // publicLookup has access to all public types/members of types in unnamed modules
! if ((lookupModes & UNCONDITIONAL) != 0
! && (lookupModes & PUBLIC) != 0
! && (!c2.getModule().isNamed())
! && Modifier.isPublic(c2.getModifiers()))
! return true;
LookupCase lc = this.in(c2);
! int m1 = lc.lookupModes();
boolean r = false;
! if (m1 == 0) {
r = false;
} else {
! int m2 = fixMods(c2.getModifiers());
! if ((m2 & PUBLIC) != 0) {
r = true;
! } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {
r = true;
}
}
if (verbosity >= 2) {
System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
--- 357,395 ----
// not visible
return false;
}
}
! Module m1 = c1.getModule();
! Module m2 = c2.getModule();
! Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1;
! // unconditional has access to all public types that is in an unconditionally exported package
! if ((lookupModes & UNCONDITIONAL) != 0) {
! return m2.isExported(c2.getPackageName()) && Modifier.isPublic(c2.getModifiers());
! }
! // c1 and c2 are in different module
! if (m1 != m2 || m0 != m2) {
! return (lookupModes & PUBLIC) != 0
! && isModuleAccessible(c2)
! && Modifier.isPublic(c2.getModifiers());
! }
!
! assert(m1 == m2 && prevLookupClass == null);
LookupCase lc = this.in(c2);
! int modes1 = lc.lookupModes();
boolean r = false;
! if (modes1 == 0) {
r = false;
} else {
! if (Modifier.isPublic(c2.getModifiers())) {
! if ((modes1 & MODULE) != 0)
r = true;
! else if ((modes1 & PUBLIC) != 0)
! r = m1.isExported(c2.getPackageName());
! } else {
! if ((modes1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage())
r = true;
}
}
if (verbosity >= 2) {
System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
*** 326,345 ****
LOADERS.add(cl);
}
return i+1;
}
! private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2) {
TreeSet<LookupCase> edges = CASE_EDGES.get(l2);
if (edges == null) CASE_EDGES.put(l2, edges = new TreeSet<>());
if (edges.add(l1)) {
Class<?> c1 = l1.lookupClass();
assert(l2.lookupClass() == c2); // [A1]
int m1 = l1.lookupModes();
int m2 = l2.lookupModes();
assert((m1 | m2) == m1); // [A2] (no elevation of access)
! LookupCase expect = l1.in(c2);
if (!expect.equals(l2))
System.out.println("*** expect "+l1+" => "+expect+" but got "+l2);
assertEquals(l2, expect);
}
}
--- 429,448 ----
LOADERS.add(cl);
}
return i+1;
}
! private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2, int dropAccess) {
TreeSet<LookupCase> edges = CASE_EDGES.get(l2);
if (edges == null) CASE_EDGES.put(l2, edges = new TreeSet<>());
if (edges.add(l1)) {
Class<?> c1 = l1.lookupClass();
assert(l2.lookupClass() == c2); // [A1]
int m1 = l1.lookupModes();
int m2 = l2.lookupModes();
assert((m1 | m2) == m1); // [A2] (no elevation of access)
! LookupCase expect = dropAccess == 0 ? l1.in(c2) : l1.in(c2).dropLookupMode(dropAccess);
if (!expect.equals(l2))
System.out.println("*** expect "+l1+" => "+expect+" but got "+l2);
assertEquals(l2, expect);
}
}
*** 356,368 ****
System.out.println("loaders = "+LOADERS);
int rounds = 0;
for (int lastCount = -1; lastCount != CASES.size(); ) {
lastCount = CASES.size(); // if CASES grow in the loop we go round again
for (LookupCase lc1 : CASES.toArray(new LookupCase[0])) {
for (Class<?> c2 : classes) {
LookupCase lc2 = new LookupCase(lc1.lookup().in(c2));
! addLookupEdge(lc1, c2, lc2);
CASES.add(lc2);
}
}
rounds++;
}
--- 459,476 ----
System.out.println("loaders = "+LOADERS);
int rounds = 0;
for (int lastCount = -1; lastCount != CASES.size(); ) {
lastCount = CASES.size(); // if CASES grow in the loop we go round again
for (LookupCase lc1 : CASES.toArray(new LookupCase[0])) {
+ for (int mode : ACCESS_CASES) {
+ LookupCase lc2 = new LookupCase(lc1.lookup().dropLookupMode(mode));
+ addLookupEdge(lc1, lc1.lookupClass(), lc2, mode);
+ CASES.add(lc2);
+ }
for (Class<?> c2 : classes) {
LookupCase lc2 = new LookupCase(lc1.lookup().in(c2));
! addLookupEdge(lc1, c2, lc2, 0);
CASES.add(lc2);
}
}
rounds++;
}
*** 384,405 ****
@Test public void test() {
makeCases(lookups());
if (verbosity > 0) {
verbosity += 9;
Method pro_in_self = targetMethod(THIS_CLASS, PROTECTED, methodType(void.class));
! testOneAccess(lookupCase("AccessControlTest/public"), pro_in_self, "find");
! testOneAccess(lookupCase("Remote_subclass/public"), pro_in_self, "find");
testOneAccess(lookupCase("Remote_subclass"), pro_in_self, "find");
verbosity -= 9;
}
Set<Class<?>> targetClassesDone = new HashSet<>();
for (LookupCase targetCase : CASES) {
Class<?> targetClass = targetCase.lookupClass();
if (!targetClassesDone.add(targetClass)) continue; // already saw this one
String targetPlace = placeName(targetClass);
if (targetPlace == null) continue; // Object, String, not a target
for (int targetAccess : ACCESS_CASES) {
MethodType methodType = methodType(void.class);
Method method = targetMethod(targetClass, targetAccess, methodType);
// Try to access target method from various contexts.
for (LookupCase sourceCase : CASES) {
testOneAccess(sourceCase, method, "findClass");
--- 492,515 ----
@Test public void test() {
makeCases(lookups());
if (verbosity > 0) {
verbosity += 9;
Method pro_in_self = targetMethod(THIS_CLASS, PROTECTED, methodType(void.class));
! testOneAccess(lookupCase("AccessControlTest/module"), pro_in_self, "find");
! testOneAccess(lookupCase("Remote_subclass/module"), pro_in_self, "find");
testOneAccess(lookupCase("Remote_subclass"), pro_in_self, "find");
verbosity -= 9;
}
Set<Class<?>> targetClassesDone = new HashSet<>();
for (LookupCase targetCase : CASES) {
Class<?> targetClass = targetCase.lookupClass();
if (!targetClassesDone.add(targetClass)) continue; // already saw this one
String targetPlace = placeName(targetClass);
if (targetPlace == null) continue; // Object, String, not a target
for (int targetAccess : ACCESS_CASES) {
+ if (targetAccess == MODULE || targetAccess == UNCONDITIONAL)
+ continue;
MethodType methodType = methodType(void.class);
Method method = targetMethod(targetClass, targetAccess, methodType);
// Try to access target method from various contexts.
for (LookupCase sourceCase : CASES) {
testOneAccess(sourceCase, method, "findClass");
*** 455,465 ****
testCount++;
if (!didAccess) testCountFails++;
}
static Method targetMethod(Class<?> targetClass, int targetAccess, MethodType methodType) {
- assert targetAccess != MODULE;
String methodName = accessName(targetAccess)+placeName(targetClass);
if (verbosity >= 2)
System.out.println(targetClass.getSimpleName()+"."+methodName+methodType);
try {
Method method = targetClass.getDeclaredMethod(methodName, methodType.parameterArray());
--- 565,574 ----
*** 489,502 ****
case PRIVATE: return "pri_in_";
}
assert(false);
return "?";
}
- // MODULE not a test case at this time
private static final int[] ACCESS_CASES = {
! PUBLIC, PACKAGE, PRIVATE, PROTECTED
};
/** Return one of the ACCESS_CASES. */
static int fixMods(int mods) {
mods &= (PUBLIC|PRIVATE|PROTECTED);
switch (mods) {
case PUBLIC: case PRIVATE: case PROTECTED: return mods;
--- 598,614 ----
case PRIVATE: return "pri_in_";
}
assert(false);
return "?";
}
private static final int[] ACCESS_CASES = {
! PUBLIC, PACKAGE, PRIVATE, PROTECTED, MODULE, UNCONDITIONAL
};
+ /*
+ * Adjust PUBLIC => PUBLIC|MODULE|UNCONDITIONAL
+ * Adjust 0 => PACKAGE
+ */
/** Return one of the ACCESS_CASES. */
static int fixMods(int mods) {
mods &= (PUBLIC|PRIVATE|PROTECTED);
switch (mods) {
case PUBLIC: case PRIVATE: case PROTECTED: return mods;
< prev index next >