Skip to content

Commit 01307a7

Browse files
committedDec 5, 2024
8341551: Revisit jdk.internal.loader.URLClassPath.JarLoader after JEP 486
Reviewed-by: dfuchs, lancea, rriggs, alanb
1 parent bcd1018 commit 01307a7

File tree

2 files changed

+150
-7
lines changed

2 files changed

+150
-7
lines changed
 

‎src/java.base/share/classes/jdk/internal/loader/URLClassPath.java

+9-7
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public class URLClassPath {
7575
private static final String USER_AGENT_JAVA_VERSION = "UA-Java-Version";
7676
private static final String JAVA_VERSION;
7777
private static final boolean DEBUG;
78-
private static final boolean DISABLE_JAR_CHECKING;
78+
private static final boolean JAR_CHECKING_ENABLED;
7979
private static final boolean DISABLE_CP_URL_CHECK;
8080
private static final boolean DEBUG_CP_URL_CHECK;
8181

@@ -84,7 +84,9 @@ public class URLClassPath {
8484
JAVA_VERSION = props.getProperty("java.version");
8585
DEBUG = (props.getProperty("sun.misc.URLClassPath.debug") != null);
8686
String p = props.getProperty("sun.misc.URLClassPath.disableJarChecking");
87-
DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.isEmpty() : false;
87+
// JAR check is disabled by default and will be enabled only if the "disable JAR check"
88+
// system property has been set to "false".
89+
JAR_CHECKING_ENABLED = "false".equals(p);
8890

8991
// This property will be removed in a later release
9092
p = props.getProperty("jdk.net.URLClassPath.disableClassPathURLCheck");
@@ -652,11 +654,12 @@ private void ensureOpen() throws IOException {
652654
}
653655
}
654656

655-
/* Throws if the given jar file is does not start with the correct LOC */
656-
@SuppressWarnings("removal")
657+
/*
658+
* Throws an IOException if the LOC file Header Signature (0x04034b50),
659+
* is not found starting at byte 0 of the given jar.
660+
*/
657661
static JarFile checkJar(JarFile jar) throws IOException {
658-
if (System.getSecurityManager() != null && !DISABLE_JAR_CHECKING
659-
&& !zipAccess.startsWithLocHeader(jar)) {
662+
if (JAR_CHECKING_ENABLED && !zipAccess.startsWithLocHeader(jar)) {
660663
IOException x = new IOException("Invalid Jar file");
661664
try {
662665
jar.close();
@@ -665,7 +668,6 @@ static JarFile checkJar(JarFile jar) throws IOException {
665668
}
666669
throw x;
667670
}
668-
669671
return jar;
670672
}
671673

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.io.IOException;
25+
import java.io.OutputStream;
26+
import java.net.URI;
27+
import java.net.URL;
28+
import java.nio.file.Files;
29+
import java.nio.file.OpenOption;
30+
import java.nio.file.Path;
31+
import java.nio.file.StandardOpenOption;
32+
import java.util.Arrays;
33+
import java.util.jar.JarEntry;
34+
import java.util.jar.JarOutputStream;
35+
import java.util.jar.Manifest;
36+
37+
import jdk.internal.loader.URLClassPath;
38+
import org.junit.jupiter.api.BeforeAll;
39+
import org.junit.jupiter.api.Test;
40+
import static java.nio.charset.StandardCharsets.US_ASCII;
41+
import static org.junit.jupiter.api.Assertions.assertNotNull;
42+
import static org.junit.jupiter.api.Assertions.assertNull;
43+
44+
/*
45+
* @test
46+
* @bug 8341551
47+
* @summary verify the behaviour of URLClassPath in the presence/absence of
48+
* sun.misc.URLClassPath.disableJarChecking system property
49+
*
50+
* @modules java.base/jdk.internal.loader
51+
*
52+
* @comment the following run is expected to run with jar checking enabled
53+
* @run junit/othervm -Dsun.misc.URLClassPath.disableJarChecking=false JarCheckTest
54+
*
55+
* @comment the following runs are expected to run with jar checking disabled
56+
* @run junit JarCheckTest
57+
* @run junit/othervm -Dsun.misc.URLClassPath.disableJarChecking= JarCheckTest
58+
* @run junit/othervm -Dsun.misc.URLClassPath.disableJarChecking JarCheckTest
59+
* @run junit/othervm -Dsun.misc.URLClassPath.disableJarChecking=true JarCheckTest
60+
* @run junit/othervm -Dsun.misc.URLClassPath.disableJarChecking=FALSE JarCheckTest
61+
* @run junit/othervm -Dsun.misc.URLClassPath.disableJarChecking=foo JarCheckTest
62+
*/
63+
public class JarCheckTest {
64+
65+
private static final Path SCRATCH_DIR = Path.of(".").normalize();
66+
private static final String SYS_PROP = "sun.misc.URLClassPath.disableJarChecking";
67+
private static final String RESOURCE_IN_NORMAL_JAR = "foo.txt";
68+
private static final String RESOURCE_IN_NOT_JUST_A_JAR = "bar.txt";
69+
70+
71+
private static final boolean jarCheckEnabled = "false".equals(System.getProperty(SYS_PROP));
72+
private static Path normalJar;
73+
private static Path notJustAJar; // JAR file with additional prefixed bytes
74+
75+
@BeforeAll
76+
static void beforeAll() throws Exception {
77+
final Path tmpDir = Files.createTempDirectory(SCRATCH_DIR, "8341551");
78+
// create a normal JAR file
79+
normalJar = tmpDir.resolve("normal.jar");
80+
createJar(normalJar, RESOURCE_IN_NORMAL_JAR, false);
81+
82+
// now create another JAR file and have its content prefixed with arbitrary bytes
83+
notJustAJar = tmpDir.resolve("notjustajar.jar");
84+
createJar(notJustAJar, RESOURCE_IN_NOT_JUST_A_JAR, true);
85+
}
86+
87+
private static void createJar(final Path targetJarFile, final String entryName,
88+
final boolean prefixArbitraryBytes)
89+
throws IOException {
90+
91+
Files.createFile(targetJarFile);
92+
if (prefixArbitraryBytes) {
93+
final byte[] arbitraryBytes = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
94+
Files.write(targetJarFile, arbitraryBytes);
95+
}
96+
final Manifest manifest = new Manifest();
97+
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
98+
final OpenOption openOption = prefixArbitraryBytes
99+
? StandardOpenOption.APPEND
100+
: StandardOpenOption.WRITE;
101+
try (OutputStream fos = Files.newOutputStream(targetJarFile, openOption);
102+
JarOutputStream jos = new JarOutputStream(fos, manifest)) {
103+
104+
final JarEntry jarEntry = new JarEntry(entryName);
105+
jos.putNextEntry(jarEntry);
106+
jos.write("hello".getBytes(US_ASCII));
107+
jos.closeEntry();
108+
}
109+
}
110+
111+
/*
112+
* Verifies that the URLClassPath always locates a resource from a normal JAR file
113+
* in the classpath and only conditionally locates a resource from a byte prefixed
114+
* JAR file in the classpath.
115+
*/
116+
@Test
117+
public void testLocateResource() throws Exception {
118+
System.out.println("JAR check enabled=" + jarCheckEnabled);
119+
final URL[] classpath = new URL[]{
120+
new URI("jar:" + normalJar.toUri() + "!/").toURL(),
121+
new URI("jar:" + notJustAJar.toUri() + "!/").toURL()
122+
};
123+
final URLClassPath urlc = new URLClassPath(classpath);
124+
try {
125+
System.out.println(urlc + " will use classpath: " + Arrays.toString(classpath));
126+
// always expected to be found
127+
assertNotNull(urlc.findResource(RESOURCE_IN_NORMAL_JAR),
128+
"missing resource " + RESOURCE_IN_NORMAL_JAR);
129+
// will be found only if jar check is disabled
130+
final URL resource = urlc.findResource(RESOURCE_IN_NOT_JUST_A_JAR);
131+
if (jarCheckEnabled) {
132+
assertNull(resource, "unexpectedly found " + RESOURCE_IN_NOT_JUST_A_JAR
133+
+ " at " + resource);
134+
} else {
135+
assertNotNull(resource, "missing resource " + RESOURCE_IN_NOT_JUST_A_JAR);
136+
}
137+
} finally {
138+
urlc.closeLoaders();
139+
}
140+
}
141+
}

1 commit comments

Comments
 (1)

openjdk-notifier[bot] commented on Dec 5, 2024

@openjdk-notifier[bot]
Please sign in to comment.