8173978: Lookup.in should allow teleporting from a lookup class in a named module without dropping all access

Reviewed-by: alanb, plevart
This commit is contained in:
Mandy Chung 2019-07-24 16:46:42 -07:00
parent 221da20713
commit 068575e9b1
26 changed files with 2259 additions and 317 deletions

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 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
@ -521,7 +521,7 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
public boolean isAccessibleFrom(Class<?> lookupClass) {
int mode = (ALL_ACCESS|MethodHandles.Lookup.PACKAGE|MethodHandles.Lookup.MODULE);
return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags,
lookupClass, mode);
lookupClass, null, mode);
}
/**
@ -930,13 +930,21 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
message += ", from public Lookup";
} else {
Module m;
Class<?> plc;
if (from instanceof MethodHandles.Lookup) {
MethodHandles.Lookup lookup = (MethodHandles.Lookup)from;
from = lookup.lookupClass();
m = lookup.lookupClass().getModule();
plc = lookup.previousLookupClass();
} else {
m = from.getClass().getModule();
m = ((Class<?>)from).getModule();
plc = null;
}
message += ", from " + from + " (" + m + ")";
if (plc != null) {
message += ", previous lookup " +
plc.getName() + " (" + plc.getModule() + ")";
}
}
}
return new IllegalAccessException(message);

File diff suppressed because it is too large Load Diff

@ -88,18 +88,20 @@ public class VerifyAccess {
* @param defc the class in which the proposed member is actually defined
* @param mods modifier flags for the proposed member
* @param lookupClass the class for which the access check is being made
* @param prevLookupClass the class for which the access check is being made
* @param allowedModes allowed modes
* @return true iff the accessing class can access such a member
*/
public static boolean isMemberAccessible(Class<?> refc, // symbolic ref class
Class<?> defc, // actual def class
int mods, // actual member mods
Class<?> lookupClass,
Class<?> prevLookupClass,
int allowedModes) {
if (allowedModes == 0) return false;
assert((allowedModes & PUBLIC) != 0 &&
(allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
assert((allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
// The symbolic reference class (refc) must always be fully verified.
if (!isClassAccessible(refc, lookupClass, allowedModes)) {
if (!isClassAccessible(refc, lookupClass, prevLookupClass, allowedModes)) {
return false;
}
// Usually refc and defc are the same, but verify defc also in case they differ.
@ -109,6 +111,7 @@ public class VerifyAccess {
switch (mods & ALL_ACCESS_MODES) {
case PUBLIC:
assert (allowedModes & PUBLIC) != 0 || (allowedModes & UNCONDITIONAL_ALLOWED) != 0;
return true; // already checked above
case PROTECTED:
assert !defc.isInterface(); // protected members aren't allowed in interfaces
@ -175,14 +178,23 @@ public class VerifyAccess {
* package that is exported to the module that contains D.
* <li>C and D are members of the same runtime package.
* </ul>
*
* @param refc the symbolic reference class to which access is being checked (C)
* @param lookupClass the class performing the lookup (D)
* @param prevLookupClass the class from which the lookup was teleported or null
* @param allowedModes allowed modes
*/
public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass,
public static boolean isClassAccessible(Class<?> refc,
Class<?> lookupClass,
Class<?> prevLookupClass,
int allowedModes) {
if (allowedModes == 0) return false;
assert((allowedModes & PUBLIC) != 0 &&
(allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
assert((allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
if ((allowedModes & PACKAGE_ALLOWED) != 0 &&
isSamePackage(lookupClass, refc))
return true;
int mods = getClassModifiers(refc);
if (isPublic(mods)) {
@ -195,37 +207,62 @@ public class VerifyAccess {
return true;
}
// trivially allow
if ((allowedModes & MODULE_ALLOWED) != 0 &&
(lookupModule == refModule))
// allow access to public types in all unconditionally exported packages
if ((allowedModes & UNCONDITIONAL_ALLOWED) != 0) {
return refModule.isExported(refc.getPackageName());
}
if (lookupModule == refModule && prevLookupClass == null) {
// allow access to all public types in lookupModule
if ((allowedModes & MODULE_ALLOWED) != 0)
return true;
assert (allowedModes & PUBLIC) != 0;
return refModule.isExported(refc.getPackageName());
}
// cross-module access
// 1. refc is in different module from lookupModule, or
// 2. refc is in lookupModule and a different module from prevLookupModule
Module prevLookupModule = prevLookupClass != null ? prevLookupClass.getModule()
: null;
assert refModule != lookupModule || refModule != prevLookupModule;
if (isModuleAccessible(refc, lookupModule, prevLookupModule))
return true;
// check readability when UNCONDITIONAL not allowed
if (((allowedModes & UNCONDITIONAL_ALLOWED) != 0)
|| lookupModule.canRead(refModule)) {
// check that refc is in an exported package
if ((allowedModes & MODULE_ALLOWED) != 0) {
if (refModule.isExported(refc.getPackageName(), lookupModule))
return true;
} else {
// exported unconditionally
if (refModule.isExported(refc.getPackageName()))
return true;
}
// not exported but allow access during VM initialization
// because java.base does not have its exports setup
if (!jdk.internal.misc.VM.isModuleSystemInited())
return true;
}
// not exported but allow access during VM initialization
// because java.base does not have its exports setup
if (!jdk.internal.misc.VM.isModuleSystemInited())
return true;
// public class not accessible to lookupClass
return false;
}
if ((allowedModes & PACKAGE_ALLOWED) != 0 &&
isSamePackage(lookupClass, refc))
return true;
return false;
}
/*
* Tests if a class or interface REFC is accessible to m1 and m2 where m2
* may be null.
*
* A class or interface REFC in m is accessible to m1 and m2 if and only if
* both m1 and m2 read m and m exports the package of REFC at least to
* both m1 and m2.
*/
public static boolean isModuleAccessible(Class<?> refc, Module m1, Module m2) {
Module refModule = refc.getModule();
assert refModule != m1 || refModule != m2;
int mods = getClassModifiers(refc);
if (isPublic(mods)) {
if (m1.canRead(refModule) && (m2 == null || m2.canRead(refModule))) {
String pn = refc.getPackageName();
// refc is exported package to at least both m1 and m2
if (refModule.isExported(pn, m1) && (m2 == null || refModule.isExported(pn, m2)))
return true;
}
}
return false;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* 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
@ -33,7 +33,6 @@ 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.*;
@ -62,23 +61,28 @@ public class AccessControlTest {
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, int lookupModes) {
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 int lookupModes() { return lookupModes; }
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; }
@ -86,12 +90,24 @@ public class AccessControlTest {
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());
}
@ -102,6 +118,7 @@ public class AccessControlTest {
}
public boolean equals(LookupCase that) {
return (this.lookupClass() == that.lookupClass() &&
this.prevLookupClass() == that.prevLookupClass() &&
this.lookupModes() == that.lookupModes());
}
@ -113,20 +130,25 @@ public class AccessControlTest {
/** 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 == (PUBLIC|UNCONDITIONAL))
else if (lookupModes == UNCONDITIONAL)
suffix = "/publicLookup";
else if (lookupModes == (PUBLIC|MODULE))
suffix = "/module";
else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
else if (lookupModes == (PUBLIC|PACKAGE)
|| lookupModes == (PUBLIC|MODULE|PACKAGE))
suffix = "/package";
else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE)
|| lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
suffix = "/private";
else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED)
|| lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
suffix = "";
else
suffix = "/#"+Integer.toHexString(lookupModes);
@ -138,41 +160,50 @@ public class AccessControlTest {
* 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.
* [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.)
* <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>
* [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. [A10]
* access capabilities as the original. [A11]
* <hr>
*/
public LookupCase in(Class<?> c2) {
Class<?> c1 = lookupClass();
int m1 = lookupModes();
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 = (c1.getModule() == c2.getModule()) ||
(!c1.getModule().isNamed() && !c2.getModule().isNamed());
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));
@ -180,40 +211,85 @@ public class AccessControlTest {
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 ((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) {
// Different package and no access to c2; lose all access.
changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A8]
// 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); // [A6]
changed |= (PACKAGE|PRIVATE|PROTECTED); // [A4]
}
if (!sameTopLevel) {
// Different top-level class. Lose PRIVATE and PROTECTED access.
changed |= (PRIVATE|PROTECTED); // [A5] [A7]
changed |= (PRIVATE|PROTECTED); // [A5]
}
if (!sameClass) {
changed |= (UNCONDITIONAL); // [A5]
} else {
assert(changed == 0); // [A10] (no deprivation if same class)
if (sameClass) {
assert(changed == 0); // [A11] (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)
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();
@ -229,33 +305,48 @@ public class AccessControlTest {
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());
}
// 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;
// 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 m1 = lc.lookupModes();
int m2 = fixMods(m.getModifiers());
int modes1 = lc.lookupModes();
int modes2 = fixMods(m.getModifiers());
// allow private lookup on nestmates. Otherwise, privacy is strictly enforced
if (c1 != c2 && ((m2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
m1 &= ~PRIVATE;
if (c1 != c2 && ((modes2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
modes1 &= ~PRIVATE;
}
// protected access is sometimes allowed
if ((m2 & PROTECTED) != 0) {
int prev = m2;
m2 |= PACKAGE; // it acts like a package method also
if ((modes2 & PROTECTED) != 0) {
int prev = modes2;
modes2 |= 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
modes2 |= 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;
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. */
@ -268,24 +359,36 @@ public class AccessControlTest {
}
}
// 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;
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 m1 = lc.lookupModes();
int modes1 = lc.lookupModes();
boolean r = false;
if (m1 == 0) {
if (modes1 == 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 (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) {
@ -328,7 +431,7 @@ public class AccessControlTest {
return i+1;
}
private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2) {
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)) {
@ -337,7 +440,7 @@ public class AccessControlTest {
int m1 = l1.lookupModes();
int m2 = l2.lookupModes();
assert((m1 | m2) == m1); // [A2] (no elevation of access)
LookupCase expect = l1.in(c2);
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);
@ -358,9 +461,14 @@ public class AccessControlTest {
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);
addLookupEdge(lc1, c2, lc2, 0);
CASES.add(lc2);
}
}
@ -386,8 +494,8 @@ public class AccessControlTest {
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("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;
}
@ -398,6 +506,8 @@ public class AccessControlTest {
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.
@ -457,7 +567,6 @@ public class AccessControlTest {
}
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);
@ -491,10 +600,13 @@ public class AccessControlTest {
assert(false);
return "?";
}
// MODULE not a test case at this time
private static final int[] ACCESS_CASES = {
PUBLIC, PACKAGE, PRIVATE, PROTECTED
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);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -106,37 +106,39 @@ public class DropLookupModeTest {
assertTrue(lookup.lookupModes() == 0);
}
@DataProvider(name = "unconditionals")
public Object[][] unconditionals() {
Lookup publicLookup = MethodHandles.publicLookup();
return new Object[][] {
{ publicLookup, Object.class },
{ publicLookup.in(String.class), String.class },
{ publicLookup.in(DropLookupModeTest.class), DropLookupModeTest.class },
};
}
/**
* Test dropLookupMode on the public Lookup.
* Test dropLookupMode on the lookup with public lookup
* and UNCONDITIONAL
*/
public void testPublicLookup() {
final Lookup publicLookup = MethodHandles.publicLookup();
final Class<?> lc = publicLookup.lookupClass();
assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL));
@Test(dataProvider = "unconditionals")
public void testUnconditionalLookup(Lookup unconditionalLookup, Class<?> expected) {
assertTrue(unconditionalLookup.lookupModes() == UNCONDITIONAL);
Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
assertTrue(lookup.lookupClass() == lc);
assertTrue(lookup.lookupModes() == PUBLIC);
assertPublicLookup(unconditionalLookup.dropLookupMode(PRIVATE), expected);
assertPublicLookup(unconditionalLookup.dropLookupMode(PROTECTED), expected);
assertPublicLookup(unconditionalLookup.dropLookupMode(PACKAGE), expected);
assertPublicLookup(unconditionalLookup.dropLookupMode(MODULE), expected);
assertPublicLookup(unconditionalLookup.dropLookupMode(PUBLIC), expected);
lookup = publicLookup.dropLookupMode(PROTECTED);
assertTrue(lookup.lookupClass() == lc);
assertTrue(lookup.lookupModes() == PUBLIC);
lookup = publicLookup.dropLookupMode(PACKAGE);
assertTrue(lookup.lookupClass() == lc);
assertTrue(lookup.lookupModes() == PUBLIC);
lookup = publicLookup.dropLookupMode(MODULE);
assertTrue(lookup.lookupClass() == lc);
assertTrue(lookup.lookupModes() == PUBLIC);
lookup = publicLookup.dropLookupMode(PUBLIC);
assertTrue(lookup.lookupClass() == lc);
// drop all access
Lookup lookup = unconditionalLookup.dropLookupMode(UNCONDITIONAL);
assertTrue(lookup.lookupClass() == expected);
assertTrue(lookup.lookupModes() == 0);
}
lookup = publicLookup.dropLookupMode(UNCONDITIONAL);
assertTrue(lookup.lookupClass() == lc);
assertTrue(lookup.lookupModes() == PUBLIC);
private void assertPublicLookup(Lookup lookup, Class<?> expected) {
assertTrue(lookup.lookupClass() == expected);
assertTrue(lookup.lookupModes() == UNCONDITIONAL);
}
@DataProvider(name = "badInput")
@ -157,4 +159,4 @@ public class DropLookupModeTest {
MethodHandles.lookup().dropLookupMode(modeToDrop);
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -82,6 +82,7 @@ public class PrivateLookupInTests {
}
// Invoke MethodHandles.privateLookupIn with a reduced-power caller
@Test(expectedExceptions = {IllegalAccessException.class})
public void testReducedAccessCallerSameModule() throws Throwable {
Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE);
assertTrue((caller.lookupModes() & PRIVATE) == 0);
@ -89,12 +90,6 @@ public class PrivateLookupInTests {
assertTrue((caller.lookupModes() & MODULE) != 0);
Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller);
assertTrue(lookup.lookupClass() == nonPublicType);
assertTrue(lookup.hasPrivateAccess());
// use it
MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class);
Object obj = mh.invokeExact();
}
// Invoke MethodHandles.privateLookupIn with the public lookup as caller

@ -0,0 +1,31 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8173978
* @build m3/* m4/* m5/* Unnamed Unnamed1
* @run testng/othervm m3/jdk.test.ModuleAccessTest
* @summary Basic test case for module access checks and Lookup.in and
* MethodHandles.privateLookupIn
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -21,4 +21,11 @@
* questions.
*/
public class Unnamed { }
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
public class Unnamed {
public static Lookup lookup() {
return MethodHandles.lookup();
}
}

@ -0,0 +1,24 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class Unnamed1 { }

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -45,7 +45,7 @@ public class Main {
private Class<?> p2_Type2; // m1, not exported
private Class<?> q1_Type1; // m2, exported
private Class<?> q2_Type2; // m2, not exported
private Class<?> x500NameClass; // java.base, not exported
private Class<?> signalClass; // java.base, not exported
private Class<?> unnamedClass; // class in unnamed module
@BeforeTest
@ -55,7 +55,7 @@ public class Main {
p2_Type2 = Class.forName("p2.Type2");
q1_Type1 = Class.forName("q1.Type1");
q2_Type2 = Class.forName("q2.Type2");
x500NameClass = Class.forName("sun.security.x509.X500Name");
signalClass = Class.forName("jdk.internal.misc.Signal");
unnamedClass = Class.forName("Unnamed");
} catch (ClassNotFoundException e) {
throw new AssertionError(e);
@ -105,7 +105,7 @@ public class Main {
// java.base
findConstructor(lookup, Object.class, void.class); // [A2]
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3]
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // [A3]
// unnamed
findConstructor(lookup, unnamedClass, void.class); // [A3]
@ -130,7 +130,7 @@ public class Main {
// java.base
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
// unnamed
findConstructor(lookup, unnamedClass, void.class);
@ -139,51 +139,70 @@ public class Main {
/**
* Hop to lookup class in another named module
*
* [A0] has no access
* [A0] has PUBLIC access if accessible; otherwise no access
* [A1] old lookup class becomes previous lookup class
*/
public void testFromNamedToNamedModule() throws Exception {
// m2/q1_Type1 is accessible to m1 whereas m2/q_Type2 is not accessible
Lookup lookup = MethodHandles.lookup().in(q1_Type1);
assertTrue(lookup.lookupModes() == 0); // [A0]
assertTrue(lookup.lookupModes() == PUBLIC); // [A0]
assertTrue(lookup.previousLookupClass() == Main.class); // [A1]
Lookup lookup2 = MethodHandles.lookup().in(q2_Type2);
assertTrue(lookup2.lookupModes() == 0); // [A0]
assertTrue(lookup2.previousLookupClass() == Main.class); // [A1]
// m1
findConstructorExpectingIAE(lookup, p1_Type1, void.class);
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
findConstructorExpectingIAE(lookup2, p1_Type1, void.class);
findConstructorExpectingIAE(lookup2, p2_Type2, void.class);
// m2
findConstructorExpectingIAE(lookup, q1_Type1, void.class);
findConstructor(lookup, q1_Type1, void.class); // m2/q1 is exported
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
findConstructorExpectingIAE(lookup2, q1_Type1, void.class);
findConstructorExpectingIAE(lookup2, q2_Type2, void.class);
// java.base
findConstructorExpectingIAE(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
findConstructorExpectingIAE(lookup2, Object.class, void.class);
findConstructorExpectingIAE(lookup2, signalClass, void.class, String.class);
// unnamed
findConstructorExpectingIAE(lookup, unnamedClass, void.class);
findConstructorExpectingIAE(lookup2, unnamedClass, void.class);
}
/**
* Hop to lookup class in an unnamed module
*
* [A0] has no access
* [A0] has PUBLIC access
*/
public void testFromNamedToUnnamedModule() throws Exception {
Lookup lookup = MethodHandles.lookup().in(unnamedClass);
assertTrue(lookup.lookupModes() == 0); // [A0]
assertTrue(lookup.lookupModes() == PUBLIC); // [A0]
// m1
findConstructorExpectingIAE(lookup, p1_Type1, void.class);
findConstructor(lookup, p1_Type1, void.class); // p1 is exported
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
// m2
findConstructorExpectingIAE(lookup, q1_Type1, void.class);
findConstructor(lookup, q1_Type1, void.class);
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
// java.base
findConstructorExpectingIAE(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
// unnamed
findConstructorExpectingIAE(lookup, unnamedClass, void.class);
findConstructor(lookup, unnamedClass, void.class);
}
/**
@ -206,7 +225,7 @@ public class Main {
// java.base
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
// unnamed
findConstructor(lookup, unnamedClass, void.class);
@ -215,11 +234,11 @@ public class Main {
/**
* MethodHandles.publicLookup()
*
* [A0] has PUBLIC|UNCONDITIONAL access
* [A0] has UNCONDITIONAL access
*/
public void testPublicLookup() throws Exception {
Lookup lookup = MethodHandles.publicLookup();
assertTrue(lookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); // A0
assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
// m1
findConstructor(lookup, p1_Type1, void.class);
@ -231,7 +250,7 @@ public class Main {
// java.base
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
// unnamed
findConstructor(lookup, unnamedClass, void.class);
@ -239,36 +258,12 @@ public class Main {
/**
* Hop from publicLookup to accessible type in java.base
*
* [A0] has UNCONDITIONAL access
*/
public void testPublicLookupToBaseModule() throws Exception {
Lookup lookup = MethodHandles.publicLookup().in(String.class);
assertTrue(lookup.lookupModes() == PUBLIC); // A0
// m1
findConstructorExpectingIAE(lookup, p1_Type1, void.class);
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
// m2
findConstructorExpectingIAE(lookup, q1_Type1, void.class);
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
// java.base
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
// unnamed
findConstructorExpectingIAE(lookup, unnamedClass, void.class);
}
/**
* Hop from publicLookup to accessible type in named module.
*
* [A0] has PUBLIC access
*/
public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception {
Lookup lookup = MethodHandles.publicLookup().in(p1_Type1);
assertTrue(lookup.lookupModes() == PUBLIC); // A0
assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
// m1
findConstructor(lookup, p1_Type1, void.class);
@ -280,7 +275,33 @@ public class Main {
// java.base
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
// unnamed
findConstructor(lookup, unnamedClass, void.class);
}
/**
* Hop from publicLookup to accessible type in named module.
*
* [A0] has UNCONDITIONAL access
*/
public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception {
Lookup lookup = MethodHandles.publicLookup().in(p1_Type1);
assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
// m1
findConstructor(lookup, p1_Type1, void.class);
findConstructorExpectingIAE(lookup, p2_Type2, void.class);
// m2
findConstructor(lookup, q1_Type1, void.class);
findConstructorExpectingIAE(lookup, q2_Type2, void.class);
// java.base
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
// unnamed
findConstructor(lookup, unnamedClass, void.class);
@ -305,7 +326,7 @@ public class Main {
// java.base
findConstructorExpectingIAE(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
// unnamed
findConstructorExpectingIAE(lookup, unnamedClass, void.class);
@ -314,11 +335,11 @@ public class Main {
/**
* Teleport from publicLookup to public type in unnamed module
*
* [A0] has PUBLIC access
* [A0] has UNCONDITIONAL access
*/
public void testPublicLookupToUnnamedModule() throws Exception {
Lookup lookup = MethodHandles.publicLookup().in(unnamedClass);
assertTrue(lookup.lookupModes() == PUBLIC); // A0
assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
// m1
findConstructor(lookup, p1_Type1, void.class);
@ -330,7 +351,7 @@ public class Main {
// java.base
findConstructor(lookup, Object.class, void.class);
findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
// unnamed
findConstructor(lookup, unnamedClass, void.class);

@ -0,0 +1,34 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package c1;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
public class C1 {
public C1() { }
public static Lookup lookup() {
return MethodHandles.lookup();
}
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package c1;
public class C2 {
public C2() { }
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package c2;
public class C3{
public C3() { }
}

@ -0,0 +1,568 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import e1.CrackM5Access;
import static java.lang.invoke.MethodHandles.Lookup.*;
import static org.testng.Assert.*;
public class ModuleAccessTest {
static ModuleLookup m3;
static ModuleLookup m4;
static ModuleLookup m5;
static Map<String, ModuleLookup> moduleLookupMap = new HashMap<>();
static Lookup privLookupIn;
static Lookup privLookupIn2;
static Lookup unnamedLookup;
static Class<?> unnamed;
static Class<?> unnamed1;
@BeforeTest
public void setup() throws Exception {
m3 = new ModuleLookup("m3", 'C');
m4 = new ModuleLookup("m4", 'D');
m5 = new ModuleLookup("m5", 'E');
moduleLookupMap.put(m3.name(), m3);
moduleLookupMap.put(m4.name(), m4);
moduleLookupMap.put(m5.name(), m5);
privLookupIn = MethodHandles.privateLookupIn(m3.type2, m3.lookup);
privLookupIn2 = MethodHandles.privateLookupIn(m4.type1, m3.lookup);
unnamed = Class.forName("Unnamed");
unnamed1 = Class.forName("Unnamed1");
unnamedLookup = (Lookup)unnamed.getMethod("lookup").invoke(null);
// m5 reads m3
CrackM5Access.addReads(m3.module);
CrackM5Access.addReads(unnamed.getModule());
}
@DataProvider(name = "samePackage")
public Object[][] samePackage() throws Exception {
return new Object[][] {
{ m3.lookup, m3.type2 },
{ privLookupIn, m3.type1 },
{ privLookupIn2, m4.type2 },
{ unnamedLookup, unnamed1 }
};
}
/**
* Test lookup.in(T) where T is in the same package of the lookup class.
*
* [A0] targetClass becomes the lookup class
* [A1] no change in previous lookup class
* [A2] PROTECTED and PRIVATE are dropped
*/
@Test(dataProvider = "samePackage")
public void testLookupInSamePackage(Lookup lookup, Class<?> targetClass) throws Exception {
Class<?> lookupClass = lookup.lookupClass();
Lookup lookup2 = lookup.in(targetClass);
assertTrue(lookupClass.getPackage() == targetClass.getPackage());
assertTrue(lookupClass.getModule() == targetClass.getModule());
assertTrue(lookup2.lookupClass() == targetClass); // [A0]
assertTrue(lookup2.previousLookupClass() == lookup.previousLookupClass()); // [A1]
assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE))); // [A2]
}
@DataProvider(name = "sameModule")
public Object[][] sameModule() throws Exception {
return new Object[][] {
{ m3.lookup, m3.type3},
{ privLookupIn, m3.type3},
{ privLookupIn2, m4.type3}
};
}
/**
* Test lookup.in(T) where T is in the same module but different package from the lookup class.
*
* [A0] targetClass becomes the lookup class
* [A1] no change in previous lookup class
* [A2] PROTECTED, PRIVATE and PACKAGE are dropped
*/
@Test(dataProvider = "sameModule")
public void testLookupInSameModule(Lookup lookup, Class<?> targetClass) throws Exception {
Class<?> lookupClass = lookup.lookupClass();
Lookup lookup2 = lookup.in(targetClass);
assertTrue(lookupClass.getPackage() != targetClass.getPackage());
assertTrue(lookupClass.getModule() == targetClass.getModule());
assertTrue(lookup2.lookupClass() == targetClass); // [A0]
assertTrue(lookup2.previousLookupClass() == lookup.previousLookupClass()); // [A1]
assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE))); // [A2]
}
@DataProvider(name = "anotherModule")
public Object[][] anotherModule() throws Exception {
return new Object[][] {
{ m3.lookup, m4.type1, m5, m5.accessibleTypesTo(m3.module, m4.module) },
{ m4.lookup, m5.type2, m3, m3.accessibleTypesTo(m4.module, m5.module) },
{ m3.lookup, m5.type1, m4, m4.accessibleTypesTo(m3.module, m5.module) },
{ m5.lookup, unnamed, m3, m3.accessibleTypesTo(m5.module, unnamed.getModule()) },
};
}
/**
* Test lookup.in(T) where T is in a different module from the lookup class.
*
* [A0] targetClass becomes the lookup class
* [A1] lookup class becomes previous lookup class
* [A2] PROTECTED, PRIVATE, PACKAGE, and MODULE are dropped
* [A3] no access to module internal types in m0 and m1
* [A4] if m1 reads m0, can access public types in m0; otherwise no access.
* [A5] can access public types in m1 exported to m0
* [A6] can access public types in m2 exported to m0 and m1
*/
@Test(dataProvider = "anotherModule")
public void testLookupInAnotherModule(Lookup lookup, Class<?> targetClass,
ModuleLookup m2, Set<Class<?>> otherTypes) throws Exception {
Class<?> lookupClass = lookup.lookupClass();
Module m0 = lookupClass.getModule();
Module m1 = targetClass.getModule();
assertTrue(m0 != m1);
assertTrue(m0.canRead(m1));
assertTrue(m1.isExported(targetClass.getPackageName(), m0));
Lookup lookup2 = lookup.in(targetClass);
assertTrue(lookup2.lookupClass() == targetClass); // [A0]
assertTrue(lookup2.previousLookupClass() == lookup.lookupClass()); // [A1]
assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE|MODULE))); // [A2]
// [A3] no access to module internal type in m0
// [A4] if m1 reads m0,
// [A4] no access to public types exported from m0 unconditionally
// [A4] no access to public types exported from m0
ModuleLookup ml0 = moduleLookupMap.get(m0.getName());
if (m1.canRead(m0)) {
for (Class<?> type : ml0.unconditionalExports()) {
testAccess(lookup2, type);
}
for (Class<?> type : ml0.qualifiedExportsTo(m1)) {
testAccess(lookup2, type);
}
} else {
findConstructorExpectingIAE(lookup2, ml0.type1, void.class);
findConstructorExpectingIAE(lookup2, ml0.type2, void.class);
findConstructorExpectingIAE(lookup2, ml0.type3, void.class);
}
// [A5] can access public types exported from m1 unconditionally
// [A5] can access public types exported from m1 to m0
if (m1.isNamed()) {
ModuleLookup ml1 = moduleLookupMap.get(m1.getName());
assertTrue(ml1.unconditionalExports().size() + ml1.qualifiedExportsTo(m0).size() > 0);
for (Class<?> type : ml1.unconditionalExports()) {
testAccess(lookup2, type);
}
for (Class<?> type : ml1.qualifiedExportsTo(m0)) {
testAccess(lookup2, type);
}
} else {
// unnamed module
testAccess(lookup2, unnamed1);
}
// [A5] can access public types exported from m2 unconditionally
// [A5] can access public types exported from m2 to m0 and m1
for (Class<?> type : otherTypes) {
assertTrue(type.getModule() == m2.module);
testAccess(lookup2, type);
}
// test inaccessible types
for (Class<?> type : Set.of(m2.type1, m2.type2, m2.type3)) {
if (!otherTypes.contains(type)) {
// type is accessible to this lookup
try {
lookup2.accessClass(type);
assertTrue(false);
} catch (IllegalAccessException e) {}
findConstructorExpectingIAE(lookup2, type, void.class);
}
}
}
public void testAccess(Lookup lookup, Class<?> type) throws Exception {
// type is accessible to this lookup
assertTrue(lookup.accessClass(type) == type);
// can find constructor
findConstructor(lookup, type, void.class);
Module m0 = lookup.previousLookupClass().getModule();
Module m1 = lookup.lookupClass().getModule();
Module m2 = type.getModule();
assertTrue(m0 != m1 && m0 != null);
assertTrue((lookup.lookupModes() & MODULE) == 0);
assertTrue(m0 != m2 || m1 != m2);
MethodHandles.Lookup lookup2 = lookup.in(type);
if (m2 == m1) {
// the same module of the lookup class
assertTrue(lookup2.lookupClass() == type);
assertTrue(lookup2.previousLookupClass() == lookup.previousLookupClass());
} else if (m2 == m0) {
// hop back to the module of the previous lookup class
assertTrue(lookup2.lookupClass() == type);
assertTrue(lookup2.previousLookupClass() == lookup.lookupClass());
} else {
// hop to a third module
assertTrue(lookup2.lookupClass() == type);
assertTrue(lookup2.previousLookupClass() == lookup.lookupClass());
assertTrue(lookup2.lookupModes() == 0);
}
}
@DataProvider(name = "thirdModule")
public Object[][] thirdModule() throws Exception {
return new Object[][] {
{ m3.lookup, m4.type1, m5.type1},
{ m3.lookup, m4.type2, m5.type1},
{ unnamedLookup, m3.type1, m4.type1 },
};
}
/**
* Test lookup.in(c1).in(c2) where c1 is in second module and c2 is in a third module.
*
* [A0] c2 becomes the lookup class
* [A1] c1 becomes previous lookup class
* [A2] all access bits are dropped
*/
@Test(dataProvider = "thirdModule")
public void testLookupInThirdModule(Lookup lookup, Class<?> c1, Class<?> c2) throws Exception {
Class<?> c0 = lookup.lookupClass();
Module m0 = c0.getModule();
Module m1 = c1.getModule();
Module m2 = c2.getModule();
assertTrue(m0 != m1 && m0 != m2 && m1 != m2);
assertTrue(m0.canRead(m1) && m0.canRead(m2));
assertTrue(m1.canRead(m2));
assertTrue(m1.isExported(c1.getPackageName(), m0));
assertTrue(m2.isExported(c2.getPackageName(), m0) && m2.isExported(c2.getPackageName(), m1));
Lookup lookup1 = lookup.in(c1);
assertTrue(lookup1.lookupClass() == c1);
assertTrue(lookup1.previousLookupClass() == c0);
assertTrue(lookup1.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE|MODULE)));
Lookup lookup2 = lookup1.in(c2);
assertTrue(lookup2.lookupClass() == c2); // [A0]
assertTrue(lookup2.previousLookupClass() == c1); // [A1]
assertTrue(lookup2.lookupModes() == 0, lookup2.toString()); // [A2]
}
@DataProvider(name = "privLookupIn")
public Object[][] privLookupIn() throws Exception {
return new Object[][] {
{ m3.lookup, m4.type1 },
{ m3.lookup, m5.type1 },
{ m4.lookup, m5.type2 },
{ m5.lookup, m3.type3 },
{ m5.lookup, unnamed }
};
}
/**
* Test privateLookupIn(T, lookup) where T is in another module
*
* [A0] full capabilities except MODULE bit
* [A1] target class becomes the lookup class
* [A2] the lookup class becomes previous lookup class
* [A3] IAE thrown if lookup has no MODULE access
*/
@Test(dataProvider = "privLookupIn")
public void testPrivateLookupIn(Lookup lookup, Class<?> targetClass) throws Exception {
Module m0 = lookup.lookupClass().getModule();
Module m1 = targetClass.getModule();
// privateLookupIn from m0 to m1
assertTrue(m0 != m1);
assertTrue(m1.isOpen(targetClass.getPackageName(), m0));
Lookup privLookup1 = MethodHandles.privateLookupIn(targetClass, lookup);
assertTrue(privLookup1.lookupModes() == (PROTECTED|PRIVATE|PACKAGE|PUBLIC)); // [A0]
assertTrue(privLookup1.lookupClass() == targetClass); // [A1]
assertTrue(privLookup1.previousLookupClass() == lookup.lookupClass()); // [A2]
// privLookup1 has no MODULE access; can't do privateLookupIn
try {
Lookup privLookup2 = MethodHandles.privateLookupIn(targetClass, privLookup1); // [A3]
assertFalse(privLookup2 != null);
} catch (IllegalAccessException e) {}
}
/**
* Test member access from the Lookup returned from privateLookupIn
*/
@Test
public void testPrivateLookupAccess() throws Exception {
Class<?> staticsClass = e1.Statics.class;
Lookup privLookup1 = MethodHandles.privateLookupIn(staticsClass, m4.lookup);
assertTrue((privLookup1.lookupModes() & MODULE) == 0);
assertTrue(privLookup1.lookupClass() == staticsClass);
assertTrue(privLookup1.previousLookupClass() == m4.lookup.lookupClass());
// access private member and default package member in m5
MethodType mtype = MethodType.methodType(void.class);
MethodHandle mh1 = privLookup1.findStatic(staticsClass, "privateMethod", mtype);
MethodHandle mh2 = privLookup1.findStatic(staticsClass, "packageMethod", mtype);
// access public member in exported types from m5 to m4
findConstructor(privLookup1, m5.type1, void.class);
// no access to public member in non-exported types to m5
findConstructorExpectingIAE(privLookup1, m5.type3, void.class);
// no access to public types in m4 since m5 does not read m4
assertFalse(m5.module.canRead(m4.module));
findConstructorExpectingIAE(privLookup1, m4.type1, void.class);
// teleport from a privateLookup to another class in the same package
// lose private access
Lookup privLookup2 = MethodHandles.privateLookupIn(m5.type1, m4.lookup);
Lookup lookup = privLookup2.in(staticsClass);
assertTrue((lookup.lookupModes() & PRIVATE) == 0);
MethodHandle mh3 = lookup.findStatic(staticsClass, "packageMethod", mtype);
try {
lookup.findStatic(staticsClass, "privateMethod", mtype);
assertTrue(false);
} catch (IllegalAccessException e) {}
}
/**
* Test member access from the Lookup returned from privateLookupIn and
* the lookup mode after dropLookupMode
*/
@Test
public void testDropLookupMode() throws Exception {
Lookup lookup = MethodHandles.privateLookupIn(m5.type1, m4.lookup);
assertTrue((lookup.lookupModes() & MODULE) == 0);
Lookup lookup1 = lookup.dropLookupMode(PRIVATE);
assertTrue(lookup1.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE)));
Lookup lookup2 = lookup.dropLookupMode(PACKAGE);
assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE)));
Lookup lookup3 = lookup.dropLookupMode(MODULE);
assertTrue(lookup3.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE)));
Lookup lookup4 = lookup.dropLookupMode(PUBLIC);
assertTrue(lookup4.lookupModes() == 0);
}
/**
* Test no access to a public member on a non-public class
*/
@Test
public void testPrivateLookupOnNonPublicType() throws Exception {
// privateLookup in a non-public type
Class<?> nonPUblicType = Class.forName("e1.NonPublic");
Lookup privLookup = MethodHandles.privateLookupIn(nonPUblicType, m4.lookup);
MethodType mtype = MethodType.methodType(void.class);
MethodHandle mh1 = privLookup.findStatic(nonPUblicType, "publicStatic", mtype);
// drop MODULE access i.e. only PUBLIC access
Lookup lookup = privLookup.dropLookupMode(MODULE);
assertTrue(lookup.lookupModes() == PUBLIC);
try {
MethodHandle mh2 = lookup.findStatic(nonPUblicType, "publicStatic", mtype);
assertFalse(mh2 != null);
} catch (IllegalAccessException e) {}
}
@Test
public void testPublicLookup() {
Lookup publicLookup = MethodHandles.publicLookup();
Lookup pub1 = publicLookup.in(m3.type1);
Lookup pub2 = pub1.in(java.lang.String.class);
Lookup pub3 = pub2.in(java.lang.management.ThreadMXBean.class);
Lookup pub4 = pub3.dropLookupMode(UNCONDITIONAL);
assertTrue(publicLookup.lookupClass() == Object.class);
assertTrue(publicLookup.lookupModes() == UNCONDITIONAL);
assertTrue(pub1.lookupClass() == m3.type1);
assertTrue(pub1.lookupModes() == UNCONDITIONAL);
assertTrue(pub2.lookupClass() == String.class);
assertTrue(pub2.lookupModes() == UNCONDITIONAL);
assertTrue(pub3.lookupClass() == java.lang.management.ThreadMXBean.class);
assertTrue(pub3.lookupModes() == UNCONDITIONAL);
assertTrue(pub4.lookupModes() == 0);
// publicLookup has no MODULE access; can't do privateLookupIn
try {
Lookup pub5 = MethodHandles.privateLookupIn(m4.type1, pub1);
assertFalse(pub5 != null);
} catch (IllegalAccessException e) {}
}
static class ModuleLookup {
private final Module module;
private final Set<String> packages;
private final Lookup lookup;
private final Class<?> type1;
private final Class<?> type2;
private final Class<?> type3;
ModuleLookup(String mn, char c) throws Exception {
this.module = ModuleLayer.boot().findModule(mn).orElse(null);
assertNotNull(this.module);
this.packages = module.getDescriptor().packages();
assertTrue(packages.size() <= 3);
Lookup lookup = null;
Class<?> type1 = null;
Class<?> type2 = null;
Class<?> type3 = null;
for (String pn : packages) {
char n = pn.charAt(pn.length() - 1);
switch (n) {
case '1':
type1 = Class.forName(pn + "." + c + "1");
type2 = Class.forName(pn + "." + c + "2");
Method m = type1.getMethod("lookup");
lookup = (Lookup) m.invoke(null);
break;
case '2':
type3 = Class.forName(pn + "." + c + "3");
break;
default:
}
}
this.lookup = lookup;
this.type1 = type1;
this.type2 = type2;
this.type3 = type3;
}
String name() {
return module.getName();
}
/*
* Returns the set of types that are unconditionally exported.
*/
Set<Class<?>> unconditionalExports() {
return Stream.of(type1, type2, type3)
.filter(c -> module.isExported(c.getPackageName()))
.collect(Collectors.toSet());
}
/*
* Returns the set of types that are qualifiedly exported to the specified
* caller module
*/
Set<Class<?>> qualifiedExportsTo(Module caller) {
if (caller.canRead(this.module)) {
return Stream.of(type1, type2, type3)
.filter(c -> !module.isExported(c.getPackageName())
&& module.isExported(c.getPackageName(), caller))
.collect(Collectors.toSet());
} else {
return Set.of();
}
}
/*
* Returns the set of types that are qualifiedly exported to the specified
* caller module
*/
Set<Class<?>> accessibleTypesTo(Module m0, Module m1) {
if (m0.canRead(this.module) && m1.canRead(this.module)) {
return Stream.of(type1, type2, type3)
.filter(c -> module.isExported(c.getPackageName(), m0)
&& module.isExported(c.getPackageName(), m1))
.collect(Collectors.toSet());
} else {
return Set.of();
}
}
/*
* Returns the set of types that are open to the specified caller
* unconditionally or qualifiedly.
*/
Set<Class<?>> opensTo(Module caller) {
if (caller.canRead(this.module)) {
return Stream.of(type1, type2, type3)
.filter(c -> module.isOpen(c.getPackageName(), caller))
.collect(Collectors.toSet());
} else {
return Set.of();
}
}
public String toString() {
return module.toString();
}
}
/**
* Invokes Lookup findConstructor with a method type constructed from the
* given return and parameter types, expecting IllegalAccessException to be
* thrown.
*/
static void findConstructorExpectingIAE(Lookup lookup,
Class<?> clazz,
Class<?> rtype,
Class<?>... ptypes) throws Exception {
try {
MethodHandle mh = findConstructor(lookup, clazz, rtype, ptypes);
assertTrue(false);
} catch (IllegalAccessException expected) { }
}
/**
* Invokes Lookup findConstructor with a method type constructored from the
* given return and parameter types.
*/
static MethodHandle findConstructor(Lookup lookup,
Class<?> clazz,
Class<?> rtype,
Class<?>... ptypes) throws Exception {
MethodType mt = MethodType.methodType(rtype, ptypes);
return lookup.findConstructor(clazz, mt);
}
}

@ -0,0 +1,32 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module m3 {
requires m4;
requires m5;
requires testng;
requires java.management;
exports c1;
opens c2 to m5;
exports jdk.test;
}

@ -0,0 +1,34 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package d1;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
public class D1 {
public D1() { }
public static Lookup lookup() {
return MethodHandles.lookup();
}
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package d1;
public class D2 {
public D2() { }
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package d2;
public class D3 {
public D3() { }
}

@ -0,0 +1,28 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module m4 {
requires m5;
opens d1;
exports d2 to m3;
}

@ -0,0 +1,33 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package e1;
public class CrackM5Access {
private static void privateMethod() { }
static void packageMethod() { }
public static void addReads(Module m) {
CrackM5Access.class.getModule().addReads(m);
}
}

@ -0,0 +1,34 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package e1;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
public class E1 {
public E1() { }
public static Lookup lookup() {
return MethodHandles.lookup();
}
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package e1;
public class E2 {
public E2() { }
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package e1;
class NonPublic {
public static void publicStatic() { }
}

@ -0,0 +1,29 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package e1;
public class Statics {
private static void privateMethod() { }
static void packageMethod() { }
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package e2;
public class E3 {
public E3() { }
}

@ -0,0 +1,28 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module m5 {
exports e1 to m3;
opens e1 to m3, m4;
exports e2 to m3;
}