Skip to content

Commit 99d4195

Browse files
committed
8345259: Disallow ALL-MODULE-PATH without explicit --module-path
1 parent 95419d9 commit 99d4195

File tree

3 files changed

+178
-10
lines changed

3 files changed

+178
-10
lines changed

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -277,14 +277,6 @@ int run(String[] args) {
277277
return EXIT_OK;
278278
}
279279

280-
if (options.modulePath.isEmpty()) {
281-
// no --module-path specified - try to set $JAVA_HOME/jmods if that exists
282-
Path jmods = getDefaultModulePath();
283-
if (jmods != null) {
284-
options.modulePath.add(jmods);
285-
}
286-
}
287-
288280
JlinkConfiguration config = initJlinkConfig();
289281
outputPath = config.getOutput();
290282
if (options.suggestProviders) {
@@ -377,6 +369,10 @@ public static void createImage(JlinkConfiguration config,
377369
// the token for "all modules on the module path"
378370
private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
379371
private JlinkConfiguration initJlinkConfig() throws BadArgs {
372+
// Empty module path not allowed with ALL-MODULE-PATH in --add-modules
373+
if (options.modulePath.isEmpty() && options.addMods.contains(ALL_MODULE_PATH)) {
374+
throw taskHelper.newBadArgs("err.all.module.path.empty.mod.path");
375+
}
380376
ModuleFinder initialFinder = createFinderFromPath(options.modulePath);
381377
boolean isLinkFromRuntime = determineLinkFromRuntime(initialFinder, options.modulePath);
382378
ModuleFinder rootsFinder = isLinkFromRuntime ? ModuleFinder.compose(ModuleFinder.ofSystem(),
@@ -386,7 +382,8 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs {
386382
assert !isLinkFromRuntime : "Expected regular JMODs based link";
387383
// External module linked into a custom runtime, but JDK modules
388384
// not observable on the module path. Add the default module path
389-
// if that exists.
385+
// if that exists. Adding it here is OK, because we limit the set
386+
// in the ALL-MODULE-PATH case using initialFinder.
390387
Path defModPath = getDefaultModulePath();
391388
if (defModPath != null) {
392389
options.modulePath.add(defModPath);
@@ -397,7 +394,22 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs {
397394
Set<String> roots = new HashSet<>();
398395
for (String mod : options.addMods) {
399396
if (mod.equals(ALL_MODULE_PATH) && options.modulePath.size() > 0) {
400-
ModuleFinder mf = newModuleFinder(rootsFinder, options.limitMods, Set.of(), isLinkFromRuntime);
397+
// Apply a module limit for the roots finder if it was otherwise empty.
398+
// Since we are using the same finder for determining the roots set as
399+
// for the actual link, we need to apply this trick so as to not
400+
// include all modules of the JDK plus the extra module path in
401+
// the roots set.
402+
Set<String> allModsLimits = options.limitMods;
403+
if (options.limitMods.isEmpty()) {
404+
Set<String> modsLimits = new HashSet<>();
405+
initialFinder.findAll()
406+
.stream()
407+
.map(ModuleReference::descriptor)
408+
.map(ModuleDescriptor::name)
409+
.forEach(mn -> modsLimits.add(mn));
410+
allModsLimits = modsLimits;
411+
}
412+
ModuleFinder mf = newModuleFinder(rootsFinder, allModsLimits, Set.of(), isLinkFromRuntime);
401413
// all observable modules are roots
402414
mf.findAll()
403415
.stream()

src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ err.runtime.link.packaged.mods=This JDK has no packaged modules.\
127127
err.runtime.link.modified.file={0} has been modified
128128
err.runtime.link.patched.module=jlink does not support linking from the run-time image\
129129
\ when running on a patched runtime with --patch-module
130+
err.all.module.path.empty.mod.path=ALL-MODULE-PATH requires --module-path option
130131
err.empty.module.path=empty module path
131132
err.jlink.version.mismatch=jlink version {0}.{1} does not match target java.base version {2}.{3}
132133
err.automatic.module:automatic module cannot be used with jlink: {0} from {1}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
* Copyright (c) 2024, Red Hat, Inc.
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.ByteArrayOutputStream;
25+
import java.io.PrintWriter;
26+
import java.nio.charset.StandardCharsets;
27+
import java.nio.file.Path;
28+
import java.util.List;
29+
import java.util.regex.Pattern;
30+
import java.util.spi.ToolProvider;
31+
import java.util.stream.Stream;
32+
33+
import jdk.test.lib.Platform;
34+
import jdk.test.lib.process.OutputAnalyzer;
35+
import jdk.test.lib.process.ProcessTools;
36+
import jdk.tools.jlink.internal.LinkableRuntimeImage;
37+
import tests.Helper;
38+
import tests.Result;
39+
40+
/*
41+
* @test
42+
* @summary Test ALL-MODULE-PATH option
43+
* @bug 8345259 8345573
44+
* @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g)
45+
* @library ../lib /test/lib
46+
* @enablePreview
47+
* @modules java.base/jdk.internal.jimage
48+
* jdk.jlink/jdk.tools.jlink.internal
49+
* jdk.jlink/jdk.tools.jlink.plugin
50+
* jdk.jlink/jdk.tools.jimage
51+
* @run main/othervm -Xmx1g AllModulePathTest
52+
*/
53+
public class AllModulePathTest {
54+
private static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
55+
.orElseThrow(() ->
56+
new RuntimeException("jlink tool not found")
57+
);
58+
59+
private final Helper helper;
60+
61+
public AllModulePathTest(Helper helper) {
62+
this.helper = helper;
63+
}
64+
65+
private void noModulePath() {
66+
Path targetPath = helper.createNewImageDir("all-mod-path-no-mod-path");
67+
List<String> allArgs = List.of("--add-modules", "ALL-MODULE-PATH",
68+
"--output", targetPath.toString());
69+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
70+
PrintWriter out = new PrintWriter(baos);
71+
ByteArrayOutputStream berrOs = new ByteArrayOutputStream();
72+
PrintWriter err = new PrintWriter(berrOs);
73+
JLINK_TOOL.run(out, err, allArgs.toArray(new String[] {}));
74+
OutputAnalyzer analyzer = new OutputAnalyzer(new String(baos.toByteArray(), StandardCharsets.UTF_8),
75+
new String(berrOs.toByteArray(), StandardCharsets.UTF_8));
76+
analyzer.stdoutShouldContain("Error");
77+
analyzer.stdoutShouldContain("ALL-MODULE-PATH requires --module-path option");
78+
}
79+
80+
private void modulePathWithLimitMods() throws Exception {
81+
Path targetPath = helper.createNewImageDir("all-mods-limit-mods");
82+
String moduleName = "com.baz.runtime";
83+
Result result = helper.generateDefaultJModule(moduleName, "jdk.jfr");
84+
Path customModulePath = result.getFile().getParent();
85+
List<String> allArgs = List.of("--add-modules", "ALL-MODULE-PATH",
86+
"--limit-modules", "jdk.jfr", // A dependency of com.baz.runtime
87+
"--module-path", customModulePath.toString(),
88+
"--output", targetPath.toString());
89+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
90+
PrintWriter out = new PrintWriter(baos);
91+
ByteArrayOutputStream berrOs = new ByteArrayOutputStream();
92+
PrintWriter err = new PrintWriter(berrOs);
93+
JLINK_TOOL.run(out, err, allArgs.toArray(new String[] {}));
94+
OutputAnalyzer analyzer = new OutputAnalyzer(new String(baos.toByteArray(), StandardCharsets.UTF_8),
95+
new String(berrOs.toByteArray(), StandardCharsets.UTF_8));
96+
analyzer.shouldBeEmpty();
97+
List<String> expected = List.of("java.base", "jdk.jfr");
98+
verifyListModules(targetPath, expected);
99+
}
100+
101+
private void modulePath() throws Exception {
102+
Path targetPath = helper.createNewImageDir("all-mod-path-w-mod-path");
103+
String moduleName = "com.foo.runtime";
104+
Result result = helper.generateDefaultJModule(moduleName, "jdk.jfr");
105+
Path customModulePath = result.getFile().getParent();
106+
List<String> allArgs = List.of("--add-modules", "ALL-MODULE-PATH",
107+
"--module-path", customModulePath.toString(),
108+
"--output", targetPath.toString(),
109+
"--verbose");
110+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
111+
PrintWriter out = new PrintWriter(baos);
112+
ByteArrayOutputStream berrOs = new ByteArrayOutputStream();
113+
PrintWriter err = new PrintWriter(berrOs);
114+
JLINK_TOOL.run(out, err, allArgs.toArray(new String[] {}));
115+
OutputAnalyzer analyzer = new OutputAnalyzer(new String(baos.toByteArray(), StandardCharsets.UTF_8),
116+
new String(berrOs.toByteArray(), StandardCharsets.UTF_8));
117+
analyzer.stderrShouldBeEmpty();
118+
analyzer.stdoutShouldContain(moduleName);
119+
analyzer.stdoutShouldContain("java.base");
120+
analyzer.stdoutShouldContain("jdk.jfr");
121+
// Verify the output image's modules
122+
List<String> expected = List.of(moduleName, "java.base", "jdk.jfr");
123+
verifyListModules(targetPath, expected);
124+
}
125+
126+
private void verifyListModules(Path targetPath, List<String> expected) throws Exception {
127+
String jlink = "java" + (Platform.isWindows() ? ".exe" : "");
128+
Path javaExe = targetPath.resolve(Path.of("bin"), Path.of(jlink));
129+
List<String> listMods = List.of(javaExe.toString(), "--list-modules");
130+
OutputAnalyzer out = ProcessTools.executeCommand(listMods.toArray(new String[] {}));
131+
if (out.getExitValue() != 0) {
132+
throw new AssertionError("java --list-modules failed");
133+
}
134+
List<String> actual = Stream.of(out.getStdout().split(Pattern.quote(System.lineSeparator())))
135+
.map(s -> { return s.split("@")[0]; })
136+
.sorted()
137+
.toList();
138+
if (!expected.equals(actual)) {
139+
throw new RuntimeException("Unexpected list of modules: " + actual + " expected: " + expected);
140+
}
141+
}
142+
143+
public static void main(String[] args) throws Exception {
144+
boolean linkableRuntime = LinkableRuntimeImage.isLinkableRuntime();
145+
Helper helper = Helper.newHelper(linkableRuntime);
146+
if (helper == null) {
147+
System.err.println("Test not run");
148+
return;
149+
}
150+
AllModulePathTest test = new AllModulePathTest(helper);
151+
test.noModulePath();
152+
test.modulePath();
153+
test.modulePathWithLimitMods();
154+
}
155+
}

0 commit comments

Comments
 (0)