Skip to content

Commit

Permalink
Better handle patched modules
Browse files Browse the repository at this point in the history
Also add a test which ensures that module patching (if present), will
get an appropriate error message.
  • Loading branch information
jerboaa committed Oct 25, 2024
1 parent ef19f0d commit c80035c
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -216,17 +216,18 @@ private void writeImage(Set<Archive> archives,
BasicImageWriter writer = new BasicImageWriter(byteOrder);
ResourcePoolManager allContent = createPoolManager(archives,
entriesForModule, byteOrder, writer);
ResourcePool result;
ResourcePool result = null;
try (DataOutputStream out = plugins.getJImageFileOutputStream()) {
result = generateJImage(allContent, writer, plugins, out, generateRuntimeImage);
} catch (RuntimeImageLinkException e) {
throwRuntimeLinkFailure(e);
}

//Handle files.
try {
plugins.storeFiles(allContent.resourcePool(), result, writer);
} catch (RuntimeImageLinkException e) {
// Propagate reason for jlink runs based on linkable JDK runtimes
throw e.getReason();
throwRuntimeLinkFailure(e);
} catch (Exception ex) {
if (JlinkTask.DEBUG) {
ex.printStackTrace();
Expand All @@ -235,6 +236,15 @@ private void writeImage(Set<Archive> archives,
}
}

private static void throwRuntimeLinkFailure(RuntimeImageLinkException e) throws IOException {
if (JlinkTask.DEBUG) {
e.getReason().printStackTrace();
}
// Propagate as IOException with appropriate message for
// jlink runs from the run-time image
throw new IOException(e.getReason().getMessage());
}

/**
* Create a jimage based on content of the given ResourcePoolManager,
* optionally creating a linkable JDK runtime.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.lang.module.ModuleReference;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
Expand Down Expand Up @@ -459,7 +460,20 @@ public long size() {
// the underlying base path is a JrtPath with the
// JrtFileSystem underneath which is able to handle
// this size query.
return Files.size(archive.getPath().resolve(resPath));
try {
return Files.size(archive.getPath().resolve(resPath));
} catch (NoSuchFileException file) {
// This indicates that we don't find the class in the
// modules image using the JRT FS provider. Yet, we find
// the class using the system module finder. Therefore,
// we have a patched module. Mention that module patching
// is not supported.
String msgFormat = "File %s not found in the modules image.\n" +
"--patch-module is not supported for run-time image linking.";
String msg = String.format(msgFormat, file.getFile());
IllegalArgumentException noModulePatch = new IllegalArgumentException(msg);
throw new RuntimeImageLinkException(noModulePatch);
}
}
} catch (IOException e) {
throw new UncheckedIOException(e);
Expand Down
1 change: 0 additions & 1 deletion test/jdk/tools/jlink/JmodLess/ModifiedFilesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public abstract class ModifiedFilesTest extends AbstractLinkableRuntimeTest {
@Override
void runTest(Helper helper) throws Exception {
Path initialImage = createRuntimeLinkImage(new BaseJlinkSpecBuilder()
//.name("java-base-jlink-with-mod")
.name(initialImageName())
.addModule("java.base")
.validatingModule("java.base")
Expand Down
122 changes: 122 additions & 0 deletions test/jdk/tools/jlink/JmodLess/PatchedJDKModuleJlinkTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2024, Red Hat, Inc.
* 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.
*/

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Predicate;
import java.util.spi.ToolProvider;

import jdk.test.lib.process.OutputAnalyzer;
import tests.Helper;


/*
* @test
* @summary Test run-time link with --patch-module. Expect failure.
* @requires (jlink.runtime.linkable & vm.compMode != "Xcomp" & os.maxMemory >= 2g)
* @library ../../lib /test/lib
* @enablePreview
* @modules java.base/jdk.internal.jimage
* jdk.jlink/jdk.tools.jlink.internal
* jdk.jlink/jdk.tools.jlink.plugin
* jdk.jlink/jdk.tools.jimage
* @build tests.* jdk.test.lib.process.OutputAnalyzer
* jdk.test.lib.process.ProcessTools
* @run main/othervm -Xmx1g PatchedJDKModuleJlinkTest
*/
public class PatchedJDKModuleJlinkTest extends AbstractLinkableRuntimeTest {

@Override
public void runTest(Helper helper) throws Exception {
String imageName = "java-base-patched";
Path runtimeLinkImage = createRuntimeLinkImage(helper, imageName + "-base");

// Prepare patched module content
Path patchSource = Path.of("java-base-patch-src");
Path pkg = patchSource.resolve("java", "lang");
Path extraClass = pkg.resolve("MyJlinkPatchInteger.java");
String source = """
package java.lang;
public class MyJlinkPatchInteger {
public int add(int a, int b) {
return a + b;
}
}
""";
Files.createDirectories(pkg);
Files.writeString(extraClass, source);
Path patchClasses = Path.of("java-base-patch-classes");
Files.createDirectories(patchClasses);
ToolProvider javac = ToolProvider.findFirst("javac")
.orElseThrow(() -> new AssertionError("javac not found"));
javac.run(System.out, System.err, new String[] {
"-d", patchClasses.toString(),
"--patch-module=java.base=" + patchSource.toAbsolutePath().toString(),
extraClass.toAbsolutePath().toString()
});

// Perform a run-time image link expecting a failure
CapturingHandler handler = new CapturingHandler();
Predicate<OutputAnalyzer> exitFailPred = new Predicate<>() {

@Override
public boolean test(OutputAnalyzer t) {
return t.getExitValue() != 0; // expect failure
}
};
jlinkUsingImage(new JlinkSpecBuilder()
.helper(helper)
.imagePath(runtimeLinkImage)
.name(imageName + "-derived")
.addModule("java.base")
.validatingModule("java.base")
.extraJlinkOpt("-J--patch-module=java.base=" +
patchClasses.toAbsolutePath().toString())
.build(), handler, exitFailPred);
OutputAnalyzer analyzer = handler.analyzer();
if (analyzer.getExitValue() == 0) {
throw new AssertionError("Expected jlink to fail due to patched module!");
}
analyzer.stdoutShouldContain("MyJlinkPatchInteger.class not found in the modules image.");
analyzer.stdoutShouldContain("--patch-module is not supported");
// Verify the error message is reasonable
analyzer.stdoutShouldNotContain("jdk.tools.jlink.internal.RunImageLinkException");
analyzer.stdoutShouldNotContain("java.lang.IllegalArgumentException");
}

private Path createRuntimeLinkImage(Helper helper, String name) throws Exception {
Path initialImage = createRuntimeLinkImage(new BaseJlinkSpecBuilder()
.name(name)
.addModule("java.base")
.validatingModule("java.base")
.helper(helper)
.build());
return initialImage;
}

public static void main(String[] args) throws Exception {
PatchedJDKModuleJlinkTest test = new PatchedJDKModuleJlinkTest();
test.run();
}

}

0 comments on commit c80035c

Please sign in to comment.