8318812: LauncherHelper.checkAndLoadMain closes jar file that's about to be re-opened

Reviewed-by: alanb, jpai, coffeys
This commit is contained in:
Christian Stein 2024-02-20 07:01:45 +00:00
parent 69a11c7f7e
commit 0d285312a9
2 changed files with 86 additions and 70 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2024, 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
@ -590,73 +590,69 @@ public final class LauncherHelper {
ostream = ps;
}
static String getMainClassFromJar(String jarname) {
String mainValue;
try (JarFile jarFile = new JarFile(jarname)) {
Manifest manifest = jarFile.getManifest();
if (manifest == null) {
abort(null, "java.launcher.jar.error2", jarname);
}
Attributes mainAttrs = manifest.getMainAttributes();
if (mainAttrs == null) {
abort(null, "java.launcher.jar.error3", jarname);
}
// Main-Class
mainValue = mainAttrs.getValue(MAIN_CLASS);
if (mainValue == null) {
abort(null, "java.launcher.jar.error3", jarname);
}
// Launcher-Agent-Class (only check for this when Main-Class present)
String agentClass = mainAttrs.getValue(LAUNCHER_AGENT_CLASS);
if (agentClass != null) {
ModuleLayer.boot().findModule("java.instrument").ifPresent(m -> {
try {
String cn = "sun.instrument.InstrumentationImpl";
Class<?> clazz = Class.forName(cn, false, null);
Method loadAgent = clazz.getMethod("loadAgent", String.class);
loadAgent.invoke(null, jarname);
} catch (Throwable e) {
if (e instanceof InvocationTargetException) e = e.getCause();
abort(e, "java.launcher.jar.error4", jarname);
}
});
}
// Add-Exports and Add-Opens
String exports = mainAttrs.getValue(ADD_EXPORTS);
if (exports != null) {
addExportsOrOpens(exports, false);
}
String opens = mainAttrs.getValue(ADD_OPENS);
if (opens != null) {
addExportsOrOpens(opens, true);
}
String enableNativeAccess = mainAttrs.getValue(ENABLE_NATIVE_ACCESS);
if (enableNativeAccess != null) {
if (!enableNativeAccess.equals("ALL-UNNAMED")) {
abort(null, "java.launcher.jar.error.illegal.ena.value", enableNativeAccess);
}
Modules.addEnableNativeAccessToAllUnnamed();
}
/*
* Hand off to FXHelper if it detects a JavaFX application
* This must be done after ensuring a Main-Class entry
* exists to enforce compliance with the jar specification
*/
if (mainAttrs.containsKey(
new Attributes.Name(JAVAFX_APPLICATION_MARKER))) {
FXHelper.setFXLaunchParameters(jarname, LM_JAR);
return FXHelper.class.getName();
}
return mainValue.trim();
} catch (IOException ioe) {
abort(ioe, "java.launcher.jar.error1", jarname);
private static String getMainClassFromJar(JarFile jarFile) throws IOException {
String jarname = jarFile.getName();
Manifest manifest = jarFile.getManifest();
if (manifest == null) {
abort(null, "java.launcher.jar.error2", jarname);
}
return null;
Attributes mainAttrs = manifest.getMainAttributes();
if (mainAttrs == null) {
abort(null, "java.launcher.jar.error3", jarname);
}
// Main-Class
String mainValue = mainAttrs.getValue(MAIN_CLASS);
if (mainValue == null) {
abort(null, "java.launcher.jar.error3", jarname);
}
// Launcher-Agent-Class (only check for this when Main-Class present)
String agentClass = mainAttrs.getValue(LAUNCHER_AGENT_CLASS);
if (agentClass != null) {
ModuleLayer.boot().findModule("java.instrument").ifPresent(m -> {
try {
String cn = "sun.instrument.InstrumentationImpl";
Class<?> clazz = Class.forName(cn, false, null);
Method loadAgent = clazz.getMethod("loadAgent", String.class);
loadAgent.invoke(null, jarname);
} catch (Throwable e) {
if (e instanceof InvocationTargetException) e = e.getCause();
abort(e, "java.launcher.jar.error4", jarname);
}
});
}
// Add-Exports and Add-Opens
String exports = mainAttrs.getValue(ADD_EXPORTS);
if (exports != null) {
addExportsOrOpens(exports, false);
}
String opens = mainAttrs.getValue(ADD_OPENS);
if (opens != null) {
addExportsOrOpens(opens, true);
}
String enableNativeAccess = mainAttrs.getValue(ENABLE_NATIVE_ACCESS);
if (enableNativeAccess != null) {
if (!enableNativeAccess.equals("ALL-UNNAMED")) {
abort(null, "java.launcher.jar.error.illegal.ena.value", enableNativeAccess);
}
Modules.addEnableNativeAccessToAllUnnamed();
}
/*
* Hand off to FXHelper if it detects a JavaFX application
* This must be done after ensuring a Main-Class entry
* exists to enforce compliance with the jar specification
*/
if (mainAttrs.containsKey(
new Attributes.Name(JAVAFX_APPLICATION_MARKER))) {
FXHelper.setFXLaunchParameters(jarname, LM_JAR);
return FXHelper.class.getName();
}
return mainValue.trim();
}
/**
@ -819,13 +815,23 @@ public final class LauncherHelper {
*/
private static Class<?> loadMainClass(int mode, String what) {
// get the class name
String cn;
String cn = null;
// In LM_JAR mode, keep the underlying file open to retain it in
// the JarFile/ZipFile cache. This will avoid needing to re-parse
// the central directory when the file is opened on the class path,
// triggered by Class.forName below.
JarFile jarFile = null;
switch (mode) {
case LM_CLASS:
cn = what;
break;
case LM_JAR:
cn = getMainClassFromJar(what);
try {
jarFile = new JarFile(what);
cn = getMainClassFromJar(jarFile);
} catch (IOException ioe) {
abort(ioe, "java.launcher.jar.error1", what);
}
break;
default:
// should never happen
@ -861,6 +867,14 @@ public final class LauncherHelper {
} catch (LinkageError le) {
abort(le, "java.launcher.cls.error4", cn,
le.getClass().getName() + ": " + le.getLocalizedMessage());
} finally {
if (jarFile != null) {
try {
jarFile.close();
} catch (IOException ioe) {
abort(ioe, "java.launcher.jar.error5", what);
}
}
}
return mainClass;
}