1 /*
2 * Copyright (c) 2014, 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 */
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Deque;
35 import java.util.List;
36 import java.util.Set;
37 import java.util.concurrent.ConcurrentLinkedDeque;
38 import java.util.concurrent.ExecutorService;
39 import java.util.concurrent.Executors;
40 import java.util.concurrent.TimeUnit;
41 import java.util.concurrent.atomic.AtomicInteger;
42 import java.util.stream.Collectors;
43 import java.util.stream.Stream;
44
45 import jdk.internal.jimage.BasicImageReader;
46 import jdk.internal.jimage.ImageLocation;
47
48 /*
49 * @test
50 * @summary Verify jimage
51 * @modules java.base/jdk.internal.jimage
52 * @run main/othervm --add-modules=ALL-SYSTEM,jdk.incubator.httpclient VerifyJimage
53 */
54
55 /**
56 * This test runs in two modes:
57 * (1) No argument: it verifies the jimage by loading all classes in the runtime
58 * (2) path of exploded modules: it compares bytes of each file in the exploded
59 * module with the entry in jimage
60 *
61 * FIXME: exception thrown when findLocation from jimage by multiple threads
62 * -Djdk.test.threads=<n> to specify the number of threads.
63 */
64 public class VerifyJimage {
65 private static final String MODULE_INFO = "module-info.class";
66 private static final Deque<String> failed = new ConcurrentLinkedDeque<>();
67
68 public static void main(String... args) throws Exception {
69
70 String home = System.getProperty("java.home");
71 Path bootimagePath = Paths.get(home, "lib", "modules");
72 if (Files.notExists(bootimagePath)) {
73 System.out.println("Test skipped, not an images build");
74 return;
75 }
76
77 long start = System.nanoTime();
78 int numThreads = Integer.getInteger("jdk.test.threads", 1);
79 List<JImageReader> readers = newJImageReaders();
80 VerifyJimage verify = new VerifyJimage(readers, numThreads);
81 if (args.length == 0) {
82 // load classes from jimage
83 verify.loadClasses();
84 } else {
85 Path dir = Paths.get(args[0]);
86 if (Files.notExists(dir) || !Files.isDirectory(dir)) {
87 throw new RuntimeException("Invalid argument: " + dir);
88 }
89 verify.compareExplodedModules(dir);
90 }
91 verify.waitForCompletion();
92 long end = System.nanoTime();
93 int entries = readers.stream()
94 .mapToInt(JImageReader::entries)
95 .sum();
96 System.out.format("%d entries %d files verified: %d ms %d errors%n",
97 entries, verify.count.get(),
98 TimeUnit.NANOSECONDS.toMillis(end - start), failed.size());
99 for (String f : failed) {
100 System.err.println(f);
101 }
102 if (!failed.isEmpty()) {
103 throw new AssertionError("Test failed");
104 }
105 }
106
107 private final AtomicInteger count = new AtomicInteger(0);
108 private final List<JImageReader> readers;
109 private final ExecutorService pool;
110
111 VerifyJimage(List<JImageReader> readers, int numThreads) {
112 this.readers = readers;
113 this.pool = Executors.newFixedThreadPool(numThreads);
114 }
115
116 private void waitForCompletion() throws InterruptedException {
117 pool.shutdown();
118 pool.awaitTermination(20, TimeUnit.SECONDS);
119 }
120
121 private void compareExplodedModules(Path dir) throws IOException {
122 System.out.println("comparing jimage with " + dir);
123
124 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
125 for (Path mdir : stream) {
126 if (Files.isDirectory(mdir)) {
127 pool.execute(new Runnable() {
128 @Override
129 public void run() {
130 try {
131 Files.find(mdir, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr)
132 -> !Files.isDirectory(p) &&
133 !mdir.relativize(p).toString().startsWith("_") &&
134 !p.getFileName().toString().equals("MANIFEST.MF"))
135 .forEach(p -> compare(mdir, p, readers));
136 } catch (IOException e) {
137 throw new UncheckedIOException(e);
138 }
139 }
140 });
141 }
142 }
143 }
144 }
145
146 private final List<String> BOOT_RESOURCES = Arrays.asList(
147 "java.base/META-INF/services/java.nio.file.spi.FileSystemProvider"
148 );
149 private final List<String> EXT_RESOURCES = Arrays.asList(
150 "jdk.zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider"
151 );
152 private final List<String> APP_RESOURCES = Arrays.asList(
153 "jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector",
154 "jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector"
155 );
156
157 private void compare(Path mdir, Path p, List<JImageReader> readers) {
158 String entry = p.getFileName().toString().equals(MODULE_INFO)
159 ? mdir.getFileName().toString() + "/" + MODULE_INFO
160 : mdir.relativize(p).toString().replace(File.separatorChar, '/');
161
162 count.incrementAndGet();
163 String file = mdir.getFileName().toString() + "/" + entry;
164 if (APP_RESOURCES.contains(file)) {
165 // skip until the service config file is merged
166 System.out.println("Skipped " + file);
167 return;
168 }
169
170 String jimage = "modules";
171 JImageReader reader = readers.stream()
172 .filter(r -> r.findLocation(entry) != null)
173 .filter(r -> jimage.isEmpty() || r.imageName().equals(jimage))
174 .findFirst().orElse(null);
175 if (reader == null) {
176 failed.add(entry + " not found: " + p.getFileName().toString());
177 } else {
178 reader.compare(entry, p);
179 }
180 }
181
182 private void loadClasses() {
183 ClassLoader loader = ClassLoader.getSystemClassLoader();
184 for (JImageReader reader : readers) {
185 Arrays.stream(reader.getEntryNames())
186 .filter(n -> n.endsWith(".class") && !n.endsWith(MODULE_INFO))
187 .forEach(n -> {
188 String cn = removeModule(n).replaceAll("\\.class$", "").replace('/', '.');
189 count.incrementAndGet();
190 try {
191 System.out.println("Loading " + cn);
192 Class.forName(cn, false, loader);
193 } catch (VerifyError ve) {
194 System.err.println("VerifyError for " + cn);
195 failed.add(reader.imageName() + ": " + cn + " not verified: " + ve.getMessage());
196 } catch (ClassNotFoundException e) {
197 failed.add(reader.imageName() + ": " + cn + " not found");
198 }
199 });
200 }
201 }
202
203 private String removeModule(String path) {
204 int index = path.indexOf('/', 1);
205 return path.substring(index + 1, path.length());
206 }
207
208 private static List<JImageReader> newJImageReaders() throws IOException {
209 String home = System.getProperty("java.home");
210 Path jimage = Paths.get(home, "lib", "modules");
211 JImageReader reader = new JImageReader(jimage);
212 List<JImageReader> result = new ArrayList<>();
213 System.out.println("opened " + jimage);
214 result.add(reader);
215 return result;
216 }
217
218 static class JImageReader extends BasicImageReader {
219 final Path jimage;
220 JImageReader(Path p) throws IOException {
221 super(p);
222 this.jimage = p;
223 }
224
225 String imageName() {
226 return jimage.getFileName().toString();
227 }
228
229 int entries() {
230 return getHeader().getTableLength();
231 }
232
233 void compare(String entry, Path p) {
234 try {
235 byte[] bytes = Files.readAllBytes(p);
|
1 /*
2 * Copyright (c) 2014, 2017, 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 */
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Deque;
35 import java.util.List;
36 import java.util.Set;
37 import java.util.concurrent.ConcurrentLinkedDeque;
38 import java.util.concurrent.ExecutorService;
39 import java.util.concurrent.Executors;
40 import java.util.concurrent.TimeUnit;
41 import java.util.concurrent.atomic.AtomicInteger;
42 import java.util.stream.Collectors;
43 import java.util.stream.Stream;
44
45 import jdk.internal.jimage.BasicImageReader;
46 import jdk.internal.jimage.ImageLocation;
47
48 /*
49 * @test
50 * @summary Verify jimage
51 * @modules java.base/jdk.internal.jimage
52 * @run main/othervm --add-modules ALL-SYSTEM VerifyJimage
53 */
54
55 /**
56 * This test runs in two modes:
57 * (1) No argument: it verifies the jimage by loading all classes in the runtime
58 * (2) path of exploded modules: it compares bytes of each file in the exploded
59 * module with the entry in jimage
60 *
61 * FIXME: exception thrown when findLocation from jimage by multiple threads
62 * -Djdk.test.threads=<n> to specify the number of threads.
63 */
64 public class VerifyJimage {
65 private static final String MODULE_INFO = "module-info.class";
66 private static final Deque<String> failed = new ConcurrentLinkedDeque<>();
67
68 public static void main(String... args) throws Exception {
69
70 String home = System.getProperty("java.home");
71 Path bootimagePath = Paths.get(home, "lib", "modules");
72 if (Files.notExists(bootimagePath)) {
73 System.out.println("Test skipped, not an images build");
74 return;
75 }
76
77 long start = System.nanoTime();
78 int numThreads = Integer.getInteger("jdk.test.threads", 1);
79 JImageReader reader = newJImageReader();
80 VerifyJimage verify = new VerifyJimage(reader, numThreads);
81 if (args.length == 0) {
82 // load classes from jimage
83 verify.loadClasses();
84 } else {
85 Path dir = Paths.get(args[0]);
86 if (Files.notExists(dir) || !Files.isDirectory(dir)) {
87 throw new RuntimeException("Invalid argument: " + dir);
88 }
89 verify.compareExplodedModules(dir);
90 }
91 verify.waitForCompletion();
92 long end = System.nanoTime();
93 int entries = reader.entries();
94 System.out.format("%d entries %d files verified: %d ms %d errors%n",
95 entries, verify.count.get(),
96 TimeUnit.NANOSECONDS.toMillis(end - start), failed.size());
97 for (String f : failed) {
98 System.err.println(f);
99 }
100 if (!failed.isEmpty()) {
101 throw new AssertionError("Test failed");
102 }
103 }
104
105 private final AtomicInteger count = new AtomicInteger(0);
106 private final JImageReader reader;
107 private final ExecutorService pool;
108
109 VerifyJimage(JImageReader reader, int numThreads) {
110 this.reader = reader;
111 this.pool = Executors.newFixedThreadPool(numThreads);
112 }
113
114 private void waitForCompletion() throws InterruptedException {
115 pool.shutdown();
116 pool.awaitTermination(20, TimeUnit.SECONDS);
117 }
118
119 private void compareExplodedModules(Path dir) throws IOException {
120 System.out.println("comparing jimage with " + dir);
121
122 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
123 for (Path mdir : stream) {
124 if (Files.isDirectory(mdir)) {
125 pool.execute(new Runnable() {
126 @Override
127 public void run() {
128 try {
129 Files.find(mdir, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr)
130 -> !Files.isDirectory(p) &&
131 !mdir.relativize(p).toString().startsWith("_") &&
132 !p.getFileName().toString().equals("MANIFEST.MF"))
133 .forEach(p -> compare(mdir, p, reader));
134 } catch (IOException e) {
135 throw new UncheckedIOException(e);
136 }
137 }
138 });
139 }
140 }
141 }
142 }
143
144 private final List<String> BOOT_RESOURCES = Arrays.asList(
145 "java.base/META-INF/services/java.nio.file.spi.FileSystemProvider"
146 );
147 private final List<String> EXT_RESOURCES = Arrays.asList(
148 "jdk.zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider"
149 );
150 private final List<String> APP_RESOURCES = Arrays.asList(
151 "jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector",
152 "jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector"
153 );
154
155 private void compare(Path mdir, Path p, JImageReader reader) {
156 String entry = p.getFileName().toString().equals(MODULE_INFO)
157 ? mdir.getFileName().toString() + "/" + MODULE_INFO
158 : mdir.relativize(p).toString().replace(File.separatorChar, '/');
159
160 count.incrementAndGet();
161 String file = mdir.getFileName().toString() + "/" + entry;
162 if (APP_RESOURCES.contains(file)) {
163 // skip until the service config file is merged
164 System.out.println("Skipped " + file);
165 return;
166 }
167
168 if (reader.findLocation(entry) != null) {
169 reader.compare(entry, p);
170 }
171 }
172
173 private void loadClasses() {
174 ClassLoader loader = ClassLoader.getSystemClassLoader();
175 Stream.of(reader.getEntryNames())
176 .filter(this::accept)
177 .map(this::toClassName)
178 .forEach(cn -> {
179 count.incrementAndGet();
180 try {
181 System.out.println("Loading " + cn);
182 Class.forName(cn, false, loader);
183 } catch (VerifyError ve) {
184 System.err.println("VerifyError for " + cn);
185 failed.add(reader.imageName() + ": " + cn + " not verified: " + ve.getMessage());
186 } catch (ClassNotFoundException e) {
187 failed.add(reader.imageName() + ": " + cn + " not found");
188 }
189 });
190 }
191
192 private String toClassName(String entry) {
193 int index = entry.indexOf('/', 1);
194 return entry.substring(index + 1, entry.length())
195 .replaceAll("\\.class$", "").replace('/', '.');
196 }
197
198 private boolean accept(String entry) {
199 int index = entry.indexOf('/', 1);
200 String mn = index > 1 ? entry.substring(1, index) : "";
201 // filter deployment modules
202 if (mn.isEmpty() || mn.contains("deploy") ||
203 mn.contains("javaws") || mn.contains("plugin")) {
204 return false;
205 }
206 return entry.endsWith(".class") && !entry.endsWith(MODULE_INFO);
207 }
208
209 private static JImageReader newJImageReader() throws IOException {
210 String home = System.getProperty("java.home");
211 Path jimage = Paths.get(home, "lib", "modules");
212 System.out.println("opened " + jimage);
213 return new JImageReader(jimage);
214 }
215
216 static class JImageReader extends BasicImageReader {
217 final Path jimage;
218 JImageReader(Path p) throws IOException {
219 super(p);
220 this.jimage = p;
221 }
222
223 String imageName() {
224 return jimage.getFileName().toString();
225 }
226
227 int entries() {
228 return getHeader().getTableLength();
229 }
230
231 void compare(String entry, Path p) {
232 try {
233 byte[] bytes = Files.readAllBytes(p);
|