8158338: Nashorn's ScriptLoader split delegation has to be adjusted
Reviewed-by: lagergren, hannesw
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Tue May 31 21:12:34 2016 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Wed Jun 01 15:17:37 2016 +0530
@@ -486,6 +486,11 @@
/** class loader to resolve classes from script. */
private final ClassLoader appLoader;
+ /*package-private*/
+ ClassLoader getAppLoader() {
+ return appLoader;
+ }
+
/** Class loader to load classes compiled from scripts. */
private final ScriptLoader scriptLoader;
@@ -501,12 +506,13 @@
/** Optional class filter to use for Java classes. Can be null. */
private final ClassFilter classFilter;
- private static final StructureLoader sharedLoader;
+ /** Process-wide singleton structure loader */
+ private static final StructureLoader theStructLoader;
private static final ConcurrentMap<String, Class<?>> structureClasses = new ConcurrentHashMap<>();
/*package-private*/ @SuppressWarnings("static-method")
- StructureLoader getSharedLoader() {
- return sharedLoader;
+ StructureLoader getStructLoader() {
+ return theStructLoader;
}
private static AccessControlContext createNoPermAccCtxt() {
@@ -526,7 +532,7 @@
static {
final ClassLoader myLoader = Context.class.getClassLoader();
- sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
+ theStructLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
@Override
public StructureLoader run() {
return new StructureLoader(myLoader);
@@ -1038,7 +1044,7 @@
}
return (Class<? extends ScriptObject>)structureClasses.computeIfAbsent(fullName, (name) -> {
try {
- return Class.forName(name, true, sharedLoader);
+ return Class.forName(name, true, theStructLoader);
} catch (final ClassNotFoundException e) {
throw new AssertionError(e);
}
@@ -1191,7 +1197,7 @@
// No verification when security manager is around as verifier
// may load further classes - which should be avoided.
if (System.getSecurityManager() == null) {
- CheckClassAdapter.verify(new ClassReader(bytecode), sharedLoader, false, new PrintWriter(System.err, true));
+ CheckClassAdapter.verify(new ClassReader(bytecode), theStructLoader, false, new PrintWriter(System.err, true));
}
}
}
@@ -1551,7 +1557,7 @@
new PrivilegedAction<ScriptLoader>() {
@Override
public ScriptLoader run() {
- return new ScriptLoader(appLoader, Context.this);
+ return new ScriptLoader(Context.this);
}
}, CREATE_LOADER_ACC_CTXT);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptLoader.java Tue May 31 21:12:34 2016 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptLoader.java Wed Jun 01 15:17:37 2016 +0530
@@ -38,8 +38,8 @@
private static final String NASHORN_PKG_PREFIX = "jdk.nashorn.internal.";
private volatile boolean structureAccessAdded;
+ private final Context context;
private final Module scriptModule;
- private final Context context;
/*package-private*/ Context getContext() {
return context;
@@ -48,8 +48,8 @@
/**
* Constructor.
*/
- ScriptLoader(final ClassLoader parent, final Context context) {
- super(parent);
+ ScriptLoader(final Context context) {
+ super(context.getStructLoader());
this.context = context;
// new scripts module, it's specific exports and read-edges
@@ -67,7 +67,7 @@
}
private Module createModule(final String moduleName) {
- final Module structMod = context.getSharedLoader().getModule();
+ final Module structMod = context.getStructLoader().getModule();
final ModuleDescriptor descriptor
= new ModuleDescriptor.Builder(moduleName)
.requires(NASHORN_MODULE.getName())
@@ -80,20 +80,45 @@
return mod;
}
-
@Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
checkPackageAccess(name);
- if (name.startsWith(NASHORN_PKG_PREFIX)) {
- final StructureLoader sharedCl = context.getSharedLoader();
- final Class<?> cl = sharedCl.loadClass(name);
- if (!structureAccessAdded && cl.getClassLoader() == sharedCl) {
+ final Class<?> cl = super.loadClass(name, resolve);
+ if (!structureAccessAdded) {
+ final StructureLoader structLoader = context.getStructLoader();
+ if (cl.getClassLoader() == structLoader) {
structureAccessAdded = true;
- sharedCl.addModuleExport(scriptModule);
+ structLoader.addModuleExport(scriptModule);
}
- return cl;
}
- return super.loadClass(name, resolve);
+ return cl;
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ final ClassLoader appLoader = context.getAppLoader();
+
+ /*
+ * If the appLoader is null, don't bother side-delegating to it!
+ * Bootloader has been already attempted via parent loader
+ * delegation from the "loadClass" method.
+ *
+ * Also, make sure that we don't delegate to the app loader
+ * for nashorn's own classes or nashorn generated classes!
+ */
+ if (appLoader == null || name.startsWith(NASHORN_PKG_PREFIX)) {
+ throw new ClassNotFoundException(name);
+ }
+
+ /*
+ * This split-delegation is used so that caller loader
+ * based resolutions of classes would work. For example,
+ * java.sql.DriverManager uses caller's class loader to
+ * get Driver instances. Without this split-delegation
+ * a script class evaluating DriverManager.getDrivers()
+ * will not get back any JDBC driver!
+ */
+ return appLoader.loadClass(name);
}
// package-private and private stuff below this point