undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
388
test/jdk/tools/jlink/plugins/LegalFilePluginTest.java
Normal file
388
test/jdk/tools/jlink/plugins/LegalFilePluginTest.java
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8169925
|
||||
* @summary Validate the license files deduplicated in the image
|
||||
* @library /test/lib
|
||||
* @modules jdk.compiler
|
||||
* jdk.jlink
|
||||
* @build jdk.test.lib.compiler.CompilerUtils
|
||||
* @run testng LegalFilePluginTest
|
||||
*/
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.test.lib.compiler.CompilerUtils;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class LegalFilePluginTest {
|
||||
static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
|
||||
.orElseThrow(() ->
|
||||
new RuntimeException("jmod tool not found")
|
||||
);
|
||||
|
||||
static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
|
||||
.orElseThrow(() ->
|
||||
new RuntimeException("jlink tool not found")
|
||||
);
|
||||
|
||||
static final Path MODULE_PATH = Paths.get(System.getProperty("java.home"), "jmods");
|
||||
static final Path SRC_DIR = Paths.get("src");
|
||||
static final Path MODS_DIR = Paths.get("mods");
|
||||
static final Path JMODS_DIR = Paths.get("jmods");
|
||||
static final Path LEGAL_DIR = Paths.get("legal");
|
||||
static final Path IMAGES_DIR = Paths.get("images");
|
||||
|
||||
static final Map<List<String>, Map<String,String>> LICENSES = Map.of(
|
||||
// Key is module name and requires
|
||||
// Value is a map of filename to the file content
|
||||
List.of("m1"), Map.of("LICENSE", "m1 LICENSE",
|
||||
"m1-license.txt", "m1 license",
|
||||
"test-license", "test license v1"),
|
||||
List.of("m2", "m1"), Map.of("m2-license", "m2 license",
|
||||
"test-license", "test license v1"),
|
||||
List.of("m3"), Map.of("m3-license.md", "m3 license",
|
||||
"test-license", "test license v3"),
|
||||
List.of("m4"), Map.of("test-license", "test license v4")
|
||||
);
|
||||
|
||||
@BeforeTest
|
||||
private void setup() throws Exception {
|
||||
List<JmodFileBuilder> builders = new ArrayList<>();
|
||||
for (Map.Entry<List<String>, Map<String,String>> e : LICENSES.entrySet()) {
|
||||
List<String> names = e.getKey();
|
||||
String mn = names.get(0);
|
||||
JmodFileBuilder builder = new JmodFileBuilder(mn);
|
||||
builders.add(builder);
|
||||
|
||||
if (names.size() > 1) {
|
||||
names.subList(1, names.size())
|
||||
.stream()
|
||||
.forEach(builder::requires);
|
||||
}
|
||||
e.getValue().entrySet()
|
||||
.stream()
|
||||
.forEach(f -> builder.licenseFile(f.getKey(), f.getValue()));
|
||||
// generate source
|
||||
builder.writeModuleInfo();
|
||||
}
|
||||
|
||||
// create jmod file
|
||||
for (JmodFileBuilder builder: builders) {
|
||||
builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String imageDir(String dir) {
|
||||
return IMAGES_DIR.resolve(dir).toString();
|
||||
}
|
||||
|
||||
|
||||
@DataProvider(name = "modules")
|
||||
public Object[][] jlinkoptions() {
|
||||
String m2TestLicenseContent =
|
||||
symlinkContent(Paths.get("legal", "m2", "test-license"),
|
||||
Paths.get("legal", "m1", "test-license"),
|
||||
"test license v1");
|
||||
// options and expected header files & man pages
|
||||
return new Object[][] {
|
||||
{ new String [] {
|
||||
"test1",
|
||||
"--add-modules=m1",
|
||||
},
|
||||
Map.of( "m1/LICENSE", "m1 LICENSE",
|
||||
"m1/m1-license.txt", "m1 license",
|
||||
"m1/test-license", "test license v1")
|
||||
},
|
||||
{ new String [] {
|
||||
"test2",
|
||||
"--add-modules=m1,m2",
|
||||
},
|
||||
Map.of( "m1/LICENSE", "m1 LICENSE",
|
||||
"m1/m1-license.txt", "m1 license",
|
||||
"m1/test-license", "test license v1",
|
||||
"m2/m2-license", "m2 license",
|
||||
"m2/test-license", m2TestLicenseContent),
|
||||
},
|
||||
{ new String [] {
|
||||
"test3",
|
||||
"--add-modules=m2,m3",
|
||||
},
|
||||
Map.of( "m1/LICENSE", "m1 LICENSE",
|
||||
"m1/m1-license.txt", "m1 license",
|
||||
"m1/test-license", "test license v1",
|
||||
"m2/m2-license", "m2 license",
|
||||
"m2/test-license", m2TestLicenseContent,
|
||||
"m3/m3-license.md", "m3 license",
|
||||
"m3/test-license", "test license v3"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static String symlinkContent(Path source, Path target, String content) {
|
||||
String osName = System.getProperty("os.name");
|
||||
if (!osName.startsWith("Windows") && MODULE_PATH.getFileSystem()
|
||||
.supportedFileAttributeViews()
|
||||
.contains("posix")) {
|
||||
// symlink created
|
||||
return content;
|
||||
} else {
|
||||
// tiny file is created
|
||||
Path symlink = source.getParent().relativize(target);
|
||||
return String.format("Please see %s", symlink.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "modules")
|
||||
public void test(String[] opts, Map<String,String> expectedFiles) throws Exception {
|
||||
if (Files.notExists(MODULE_PATH)) {
|
||||
// exploded image
|
||||
return;
|
||||
}
|
||||
|
||||
String dir = opts[0];
|
||||
List<String> options = new ArrayList<>();
|
||||
for (int i = 1; i < opts.length; i++) {
|
||||
options.add(opts[i]);
|
||||
}
|
||||
|
||||
String mpath = MODULE_PATH.toString() + File.pathSeparator +
|
||||
JMODS_DIR.toString();
|
||||
Stream.of("--module-path", mpath,
|
||||
"--output", imageDir(dir))
|
||||
.forEach(options::add);
|
||||
|
||||
Path image = createImage(dir, options);
|
||||
|
||||
Files.walk(image.resolve("legal"), Integer.MAX_VALUE)
|
||||
.filter(p -> Files.isRegularFile(p))
|
||||
.filter(p -> p.getParent().endsWith("m1") ||
|
||||
p.getParent().endsWith("m2") ||
|
||||
p.getParent().endsWith("m3") ||
|
||||
p.getParent().endsWith("m4"))
|
||||
.forEach(p -> {
|
||||
String fn = image.resolve("legal").relativize(p)
|
||||
.toString()
|
||||
.replace(File.separatorChar, '/');
|
||||
System.out.println(fn);
|
||||
if (!expectedFiles.containsKey(fn)) {
|
||||
throw new RuntimeException(fn + " should not be in the image");
|
||||
}
|
||||
compareFileContent(p, expectedFiles.get(fn));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorIfNotSameContent() {
|
||||
if (Files.notExists(MODULE_PATH)) {
|
||||
// exploded image
|
||||
return;
|
||||
}
|
||||
|
||||
String dir = "test";
|
||||
|
||||
String mpath = MODULE_PATH.toString() + File.pathSeparator +
|
||||
JMODS_DIR.toString();
|
||||
List<String> options = Stream.of("--dedup-legal-notices",
|
||||
"error-if-not-same-content",
|
||||
"--module-path", mpath,
|
||||
"--add-modules=m3,m4",
|
||||
"--output", imageDir(dir))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(writer);
|
||||
System.out.println("jlink " + options.stream().collect(Collectors.joining(" ")));
|
||||
int rc = JLINK_TOOL.run(pw, pw,
|
||||
options.toArray(new String[0]));
|
||||
assertTrue(rc != 0);
|
||||
assertTrue(writer.toString().trim()
|
||||
.matches("Error:.*/m4/legal/m4/test-license .*contain different content"));
|
||||
}
|
||||
|
||||
private void compareFileContent(Path file, String content) {
|
||||
try {
|
||||
byte[] bytes = Files.readAllBytes(file);
|
||||
byte[] expected = String.format("%s%n", content).getBytes();
|
||||
assertEquals(bytes, expected, String.format("%s not matched:%nfile: %s%nexpected:%s%n",
|
||||
file.toString(), new String(bytes), new String(expected)));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Path createImage(String outputDir, List<String> options) {
|
||||
System.out.println("jlink " + options.stream().collect(Collectors.joining(" ")));
|
||||
int rc = JLINK_TOOL.run(System.out, System.out,
|
||||
options.toArray(new String[0]));
|
||||
assertTrue(rc == 0);
|
||||
|
||||
return IMAGES_DIR.resolve(outputDir);
|
||||
}
|
||||
|
||||
private void deleteDirectory(Path dir) throws IOException {
|
||||
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
throws IOException
|
||||
{
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
|
||||
throws IOException
|
||||
{
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to create JMOD file
|
||||
*/
|
||||
class JmodFileBuilder {
|
||||
|
||||
final String name;
|
||||
final Set<String> requires = new HashSet<>();
|
||||
final Map<String, String> licenses = new HashMap<>();
|
||||
|
||||
JmodFileBuilder(String name) throws IOException {
|
||||
this.name = name;
|
||||
|
||||
Path msrc = SRC_DIR.resolve(name);
|
||||
if (Files.exists(msrc)) {
|
||||
deleteDirectory(msrc);
|
||||
}
|
||||
}
|
||||
|
||||
JmodFileBuilder writeModuleInfo()throws IOException {
|
||||
Path msrc = SRC_DIR.resolve(name);
|
||||
Files.createDirectories(msrc);
|
||||
Path minfo = msrc.resolve("module-info.java");
|
||||
try (BufferedWriter bw = Files.newBufferedWriter(minfo);
|
||||
PrintWriter writer = new PrintWriter(bw)) {
|
||||
writer.format("module %s {%n", name);
|
||||
for (String req : requires) {
|
||||
writer.format(" requires %s;%n", req);
|
||||
}
|
||||
writer.format("}%n");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
JmodFileBuilder licenseFile(String filename, String content) {
|
||||
licenses.put(filename, content);
|
||||
return this;
|
||||
}
|
||||
|
||||
JmodFileBuilder requires(String name) {
|
||||
requires.add(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
Path build() throws IOException {
|
||||
compileModule();
|
||||
|
||||
Path mdir = LEGAL_DIR.resolve(name);
|
||||
for (Map.Entry<String,String> e : licenses.entrySet()) {
|
||||
Files.createDirectories(mdir);
|
||||
String filename = e.getKey();
|
||||
String content = e.getValue();
|
||||
Path file = mdir.resolve(filename);
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(file);
|
||||
PrintWriter pw = new PrintWriter(writer)) {
|
||||
pw.println(content);
|
||||
}
|
||||
}
|
||||
|
||||
return createJmodFile();
|
||||
}
|
||||
|
||||
|
||||
void compileModule() throws IOException {
|
||||
Path msrc = SRC_DIR.resolve(name);
|
||||
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
|
||||
"--module-source-path",
|
||||
SRC_DIR.toString()));
|
||||
}
|
||||
|
||||
Path createJmodFile() throws IOException {
|
||||
Path mclasses = MODS_DIR.resolve(name);
|
||||
Files.createDirectories(JMODS_DIR);
|
||||
Path outfile = JMODS_DIR.resolve(name + ".jmod");
|
||||
List<String> args = new ArrayList<>();
|
||||
args.add("create");
|
||||
// add classes
|
||||
args.add("--class-path");
|
||||
args.add(mclasses.toString());
|
||||
if (licenses.size() > 0) {
|
||||
args.add("--legal-notices");
|
||||
args.add(LEGAL_DIR.resolve(name).toString());
|
||||
}
|
||||
args.add(outfile.toString());
|
||||
|
||||
if (Files.exists(outfile))
|
||||
Files.delete(outfile);
|
||||
|
||||
System.out.println("jmod " +
|
||||
args.stream().collect(Collectors.joining(" ")));
|
||||
|
||||
int rc = JMOD_TOOL.run(System.out, System.out,
|
||||
args.toArray(new String[args.size()]));
|
||||
if (rc != 0) {
|
||||
throw new AssertionError("jmod failed: rc = " + rc);
|
||||
}
|
||||
return outfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue