Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Red Hat, Inc.
* Copyright (c) 2024, 2025, 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
Expand Down Expand Up @@ -41,10 +41,12 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -74,6 +76,7 @@ public class JRTArchive implements Archive {
// Maps a module resource path to the corresponding diff to packaged
// modules for that resource (if any)
private final Map<String, ResourceDiff> resDiff;
private final Map<String, Set<String>> altHashSums;
private final boolean errorOnModifiedFile;
private final TaskHelper taskHelper;

Expand All @@ -86,11 +89,15 @@ public class JRTArchive implements Archive {
* install aborts the link.
* @param perModDiff The lib/modules (a.k.a jimage) diff for this module,
* possibly an empty list if there are no differences.
* @param altHashSums A map of alternative hash sums for files in
* a module, possibly empty.
* @param taskHelper The task helper reference.
*/
JRTArchive(String module,
Path path,
boolean errorOnModifiedFile,
List<ResourceDiff> perModDiff,
Map<String, Set<String>> altHashSums,
TaskHelper taskHelper) {
this.module = module;
this.path = path;
Expand All @@ -105,6 +112,7 @@ public class JRTArchive implements Archive {
this.resDiff = Objects.requireNonNull(perModDiff).stream()
.collect(Collectors.toMap(ResourceDiff::getName, Function.identity()));
this.taskHelper = taskHelper;
this.altHashSums = altHashSums;
}

@Override
Expand Down Expand Up @@ -217,7 +225,21 @@ private void addNonClassResources() {

// Read from the base JDK image.
Path path = BASE.resolve(m.resPath);
if (shaSumMismatch(path, m.hashOrTarget, m.symlink)) {
// Allow for additional hash sums so as to support
// file modifications done after jlink has run at build
// time. For example for Windows builds done with
// --with-external-symbols-in-bundles=public or
// distribution builds, where some post-processing happens
// on produced binaries and libraries invalidating the
// hash sum included in the jdk.jlink module for those
// files at jlink-time
Set<String> shaSums = new HashSet<>();
shaSums.add(m.hashOrTarget);
Set<String> extra = altHashSums.get(m.resPath);
if (extra != null) {
shaSums.addAll(extra);
}
if (shaSumMismatch(path, shaSums, m.symlink)) {
if (errorOnModifiedFile) {
String msg = taskHelper.getMessage("err.runtime.link.modified.file", path.toString());
IOException cause = new IOException(msg);
Expand All @@ -239,14 +261,12 @@ private void addNonClassResources() {
}
}

static boolean shaSumMismatch(Path res, String expectedSha, boolean isSymlink) {
static boolean shaSumMismatch(Path res, Set<String> expectedShas, boolean isSymlink) {
if (isSymlink) {
return false;
}
// handle non-symlink resources
try {
HexFormat format = HexFormat.of();
byte[] expected = format.parseHex(expectedSha);
MessageDigest digest = MessageDigest.getInstance("SHA-512");
try (InputStream is = Files.newInputStream(res)) {
byte[] buf = new byte[1024];
Expand All @@ -256,7 +276,9 @@ static boolean shaSumMismatch(Path res, String expectedSha, boolean isSymlink) {
}
}
byte[] actual = digest.digest();
return !MessageDigest.isEqual(expected, actual);
// Convert actual to string
String strActual = HexFormat.of().formatHex(actual);
return !expectedShas.contains(strActual);
} catch (Exception e) {
throw new AssertionError("SHA-512 sum check failed!", e);
}
Expand Down
12 changes: 6 additions & 6 deletions src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, 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
Expand Down Expand Up @@ -148,7 +148,7 @@ public static final class JlinkConfiguration {
private final Set<String> modules;
private final ModuleFinder finder;
private final boolean linkFromRuntimeImage;
private final boolean ignoreModifiedRuntime;
private final LinkableRuntimeImage.Config runtimeImageConfig;
private final boolean generateRuntimeImage;

/**
Expand All @@ -162,13 +162,13 @@ public JlinkConfiguration(Path output,
Set<String> modules,
ModuleFinder finder,
boolean linkFromRuntimeImage,
boolean ignoreModifiedRuntime,
LinkableRuntimeImage.Config runtimeImageConfig,
boolean generateRuntimeImage) {
this.output = output;
this.modules = Objects.requireNonNull(modules);
this.finder = finder;
this.linkFromRuntimeImage = linkFromRuntimeImage;
this.ignoreModifiedRuntime = ignoreModifiedRuntime;
this.runtimeImageConfig = runtimeImageConfig;
this.generateRuntimeImage = generateRuntimeImage;
}

Expand Down Expand Up @@ -198,8 +198,8 @@ public boolean linkFromRuntimeImage() {
return linkFromRuntimeImage;
}

public boolean ignoreModifiedRuntime() {
return ignoreModifiedRuntime;
public LinkableRuntimeImage.Config runtimeImageConfig() {
return runtimeImageConfig;
}

public boolean isGenerateRuntimeImage() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, 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
Expand Down Expand Up @@ -191,7 +191,43 @@ public class JlinkTask {
// be used for linking from the run-time image.
new Option<JlinkTask>(false, (task, opt, arg) -> {
task.options.generateLinkableRuntime = true;
}, true, "--generate-linkable-runtime")
}, true, "--generate-linkable-runtime"),
new Option<JlinkTask>(true, (task, opt, arg) -> {
if (arg.startsWith("@")) {
// Read overrides from file
if (!task.options.shaOverrides.isEmpty()) {
// Only allow a single @file value
throw taskHelper.newBadArgs("err.sha.overrides.multiple");
}
// Ignore non-existing sha overrides file.
//
// This is to allow for custom builds needing to optionally
// support run-time image links on (possibly) modified
// binaries/debuginfo files done after the JDK build
//
// Allow for JAVA_HOME relative paths for the file, by replacing
// the ${java.home} token in the file name
String fileName = arg.substring(1);
if (fileName.startsWith("${java.home}")) {
String javaHome = System.getProperty("java.home");
fileName = javaHome + fileName.substring(12 /* ${java.home}.length() */);
}
Path file = Paths.get(fileName);
if (Files.exists(file)) {
try {
Files.readAllLines(file).stream()
.forEach(task.options.shaOverrides::add);
} catch (IOException e) {
throw taskHelper.newBadArgs("err.sha.overrides.freaderr", file.toString());
}
}
} else {
// Allow multiple values, separated by comma in addition to
// multiple times the same option.
Arrays.asList(arg.split(",")).stream()
.forEach(task.options.shaOverrides::add);
}
}, true, "--sha-overrides"),
};


Expand Down Expand Up @@ -235,6 +271,7 @@ static class OptionsValues {
boolean suggestProviders = false;
boolean ignoreModifiedRuntime = false;
boolean generateLinkableRuntime = false;
final Set<String> shaOverrides = new HashSet<>();
}

public static final String OPTIONS_RESOURCE = "jdk/tools/jlink/internal/options";
Expand Down Expand Up @@ -459,14 +496,41 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs {
throw taskHelper.newBadArgs("err.runtime.link.packaged.mods");
}

LinkableRuntimeImage.Config linkableRuntimeConfig = new LinkableRuntimeImage.Config(
options.ignoreModifiedRuntime,
isLinkFromRuntime ? buildShaSumMap(taskHelper, options.shaOverrides) : null);
return new JlinkConfiguration(options.output,
roots,
finder,
isLinkFromRuntime,
options.ignoreModifiedRuntime,
linkableRuntimeConfig,
options.generateLinkableRuntime);
}

private Map<String, Map<String, Set<String>>> buildShaSumMap(TaskHelper taskHelper,
Set<String> shaOverrides) throws BadArgs {
Map<String, Map<String, Set<String>>> moduleToFiles = new HashMap<>();
for (String t: shaOverrides) {
String trimmed = t.trim();
if (trimmed.startsWith("#")) {
// skip comment lines
continue;
}
String[] tokens = trimmed.split("\\|");
if (tokens.length != 3) {
throw taskHelper.newBadArgs("err.sha.overrides.bad.format", t);
}
// t is a '|'-separated item of (in that order):
// <module-name>
// <file-path>
// <SHA-512-sum>
Map<String, Set<String>> perModuleMap = moduleToFiles.computeIfAbsent(tokens[0], k -> new HashMap<>());
Set<String> shaSumsPerFile = perModuleMap.computeIfAbsent(tokens[1], k -> new HashSet<>());
shaSumsPerFile.add(tokens[2]);
}
return moduleToFiles;
}

/*
* Creates a ModuleFinder for the given module paths.
*/
Expand Down Expand Up @@ -788,7 +852,7 @@ private static Archive newArchive(String module,
taskHelper.getMessage("err.not.a.module.directory", path));
}
} else if (config.linkFromRuntimeImage()) {
return LinkableRuntimeImage.newArchive(module, path, config.ignoreModifiedRuntime(), taskHelper);
return LinkableRuntimeImage.newArchive(module, path, config.runtimeImageConfig(), taskHelper);
} else {
throw new IllegalArgumentException(
taskHelper.getMessage("err.not.modular.format", module, path));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Red Hat, Inc.
* Copyright (c) 2024, 2025, 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
Expand Down Expand Up @@ -29,6 +29,8 @@
import java.io.InputStream;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jdk.tools.jlink.internal.runtimelink.ResourceDiff;

Expand Down Expand Up @@ -67,7 +69,7 @@ private static InputStream getDiffInputStream(String module) throws IOException

public static Archive newArchive(String module,
Path path,
boolean ignoreModifiedRuntime,
Config config,
TaskHelper taskHelper) {
assert isLinkableRuntime();
// Here we retrieve the per module difference file, which is
Expand All @@ -81,8 +83,15 @@ public static Archive newArchive(String module,
throw new AssertionError("Failure to retrieve resource diff for " +
"module " + module, e);
}
return new JRTArchive(module, path, !ignoreModifiedRuntime, perModuleDiff, taskHelper);
return new JRTArchive(module,
path,
!config.ignoreModifiedRuntime,
perModuleDiff,
// Empty map if no alternative sha sums
config.altHashSums.computeIfAbsent(module, k -> Map.of()),
taskHelper);
}


static record Config(boolean ignoreModifiedRuntime,
Map<String, Map<String, Set<String>>> altHashSums) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ err.runtime.link.packaged.mods=This JDK has no packaged modules.\
err.runtime.link.modified.file={0} has been modified
err.runtime.link.patched.module=jlink does not support linking from the run-time image\
\ when running on a patched runtime with --patch-module

# Linking from the run-time image, SHA sum handling
err.sha.overrides.multiple=option --sha-overrides does not allow @file and non-file combinations
err.sha.overrides.freaderr=Error reading file ''{0}'' passed with option --sha-overrides
err.sha.overrides.bad.format=Bad format in --sha-overrides. Token was {0}. Expected <module-name>|<file-path>|<sha-sum>

err.no.module.path=--module-path option must be specified with --add-modules ALL-MODULE-PATH
err.empty.module.path=No module found in module path ''{0}'' with --add-modules ALL-MODULE-PATH
err.limit.modules=--limit-modules not allowed with --add-modules ALL-MODULE-PATH
Expand Down
4 changes: 2 additions & 2 deletions test/jdk/tools/jlink/IntegrationTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, 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
Expand Down Expand Up @@ -159,7 +159,7 @@ private static void test() throws Exception {
mods,
JlinkTask.limitFinder(JlinkTask.newModuleFinder(modulePaths), limits, mods),
linkFromRuntime,
false /* ignore modified runtime */,
null /* run-time image link config */,
false /* generate run-time image */);

List<Plugin> lst = new ArrayList<>();
Expand Down
1 change: 0 additions & 1 deletion test/jdk/tools/jlink/runtimeImage/AddOptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
* @summary Test --add-options jlink plugin when linking from the run-time image
* @requires (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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
* but java.xml.jmod present. It should link from the run-time image without errors.
* @requires (jlink.packagedModules & 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
Expand Down
1 change: 0 additions & 1 deletion test/jdk/tools/jlink/runtimeImage/BasicJlinkTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
* @summary Test basic linking from the run-time image
* @requires (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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
* @summary Test jmod-less jlink with a custom module
* @requires (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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
* @summary Verify JLI class generation in run-time image link mode
* @requires (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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
* image.
* @requires (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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
* --keep-packaged-modules fails as expected.
* @requires (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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
* and files have been modified
* @requires (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
Expand Down
Loading
Loading