Skip to content

Commit 0be3f16

Browse files
committed
8341608: jdeps in JDK 23 crashes when parsing signatures while jdeps in JDK 22 works fine
Reviewed-by: jpai, henryjen
1 parent f880fa9 commit 0be3f16

File tree

8 files changed

+241
-156
lines changed

8 files changed

+241
-156
lines changed

src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java

Lines changed: 45 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -41,10 +41,9 @@
4141
import java.nio.file.Path;
4242
import java.util.ArrayList;
4343
import java.util.Collections;
44-
import java.util.Iterator;
4544
import java.util.List;
46-
import java.util.NoSuchElementException;
4745
import java.util.Set;
46+
import java.util.function.Consumer;
4847
import java.util.jar.JarEntry;
4948
import java.util.jar.JarFile;
5049
import java.util.stream.Collectors;
@@ -102,6 +101,10 @@ public List<String> skippedEntries() {
102101
return skippedEntries;
103102
}
104103

104+
protected void skipEntry(Throwable ex, String entryPath) {
105+
skippedEntries.add(String.format("%s: %s", ex.toString(), entryPath));
106+
}
107+
105108
/**
106109
* Returns all entries in this archive.
107110
*/
@@ -135,8 +138,15 @@ public ClassModel getClassFile(String name) throws IOException {
135138
return null;
136139
}
137140

138-
public Iterable<ClassModel> getClassFiles() throws IOException {
139-
return FileIterator::new;
141+
public void forEachClassFile(Consumer<ClassModel> handler) throws IOException {
142+
if (baseFileName.endsWith(".class")) {
143+
// propagate ClassFileError for single file
144+
try {
145+
handler.accept(readClassFile(path));
146+
} catch (ClassFileError ex) {
147+
skipEntry(ex, path.toString());
148+
}
149+
}
140150
}
141151

142152
protected ClassModel readClassFile(Path p) throws IOException {
@@ -167,33 +177,6 @@ static boolean isClass(Path file) {
167177
public void close() throws IOException {
168178
}
169179

170-
class FileIterator implements Iterator<ClassModel> {
171-
int count;
172-
FileIterator() {
173-
this.count = 0;
174-
}
175-
public boolean hasNext() {
176-
return count == 0 && baseFileName.endsWith(".class");
177-
}
178-
179-
public ClassModel next() {
180-
if (!hasNext()) {
181-
throw new NoSuchElementException();
182-
}
183-
try {
184-
ClassModel cf = readClassFile(path);
185-
count++;
186-
return cf;
187-
} catch (IOException e) {
188-
throw new ClassFileError(e);
189-
}
190-
}
191-
192-
public void remove() {
193-
throw new UnsupportedOperationException("Not supported yet.");
194-
}
195-
}
196-
197180
public String toString() {
198181
return path.toString();
199182
}
@@ -241,42 +224,17 @@ public ClassModel getClassFile(String name) throws IOException {
241224
return null;
242225
}
243226

244-
public Iterable<ClassModel> getClassFiles() throws IOException {
245-
final Iterator<ClassModel> iter = new DirectoryIterator();
246-
return () -> iter;
247-
}
248-
249-
class DirectoryIterator implements Iterator<ClassModel> {
250-
private final List<Path> entries;
251-
private int index = 0;
252-
DirectoryIterator() throws IOException {
253-
List<Path> paths = null;
254-
try (Stream<Path> stream = Files.walk(path, Integer.MAX_VALUE)) {
255-
paths = stream.filter(ClassFileReader::isClass).toList();
256-
257-
}
258-
this.entries = paths;
259-
this.index = 0;
260-
}
261-
262-
public boolean hasNext() {
263-
return index != entries.size();
264-
}
265-
266-
public ClassModel next() {
267-
if (!hasNext()) {
268-
throw new NoSuchElementException();
269-
}
270-
Path path = entries.get(index++);
271-
try {
272-
return readClassFile(path);
273-
} catch (IOException e) {
274-
throw new ClassFileError(e);
275-
}
276-
}
277-
278-
public void remove() {
279-
throw new UnsupportedOperationException("Not supported yet.");
227+
@Override
228+
public void forEachClassFile(Consumer<ClassModel> handler) throws IOException {
229+
try (Stream<Path> stream = Files.walk(path, Integer.MAX_VALUE)) {
230+
stream.filter(ClassFileReader::isClass)
231+
.forEach(e -> {
232+
try {
233+
handler.accept(readClassFile(e));
234+
} catch (ClassFileError | IOException ex) {
235+
skipEntry(ex, e.toString());
236+
}
237+
});
280238
}
281239
}
282240
}
@@ -314,14 +272,15 @@ private static JarFile openJarFile(File f, Runtime.Version version)
314272
return jf;
315273
}
316274

275+
private static boolean isJarEntryClass(JarEntry e) {
276+
return e.getName().endsWith(".class");
277+
}
278+
317279
protected Set<String> scan() {
318-
try (JarFile jf = openJarFile(path.toFile(), version)) {
319-
return jf.versionedStream().map(JarEntry::getName)
320-
.filter(n -> n.endsWith(".class"))
321-
.collect(Collectors.toSet());
322-
} catch (IOException e) {
323-
throw new UncheckedIOException(e);
324-
}
280+
return jarfile.versionedStream()
281+
.filter(JarFileReader::isJarEntryClass)
282+
.map(JarEntry::getName)
283+
.collect(Collectors.toSet());
325284
}
326285

327286
public ClassModel getClassFile(String name) throws IOException {
@@ -358,76 +317,17 @@ protected ClassModel readClassFile(JarFile jarfile, JarEntry e) throws IOExcepti
358317
}
359318
}
360319

361-
public Iterable<ClassModel> getClassFiles() throws IOException {
362-
final Iterator<ClassModel> iter = new JarFileIterator(this, jarfile);
363-
return () -> iter;
364-
}
365-
}
366-
367-
class JarFileIterator implements Iterator<ClassModel> {
368-
protected final JarFileReader reader;
369-
protected Iterator<JarEntry> entries;
370-
protected JarFile jf;
371-
protected JarEntry nextEntry;
372-
protected ClassModel cf;
373-
JarFileIterator(JarFileReader reader) {
374-
this(reader, null);
375-
}
376-
JarFileIterator(JarFileReader reader, JarFile jarfile) {
377-
this.reader = reader;
378-
setJarFile(jarfile);
379-
}
380-
381-
void setJarFile(JarFile jarfile) {
382-
if (jarfile == null) return;
383-
384-
this.jf = jarfile;
385-
this.entries = jarfile.versionedStream().iterator();
386-
this.nextEntry = nextEntry();
387-
}
388-
389-
public boolean hasNext() {
390-
if (nextEntry != null && cf != null) {
391-
return true;
392-
}
393-
while (nextEntry != null) {
394-
try {
395-
cf = reader.readClassFile(jf, nextEntry);
396-
return true;
397-
} catch (ClassFileError | IOException ex) {
398-
skippedEntries.add(String.format("%s: %s (%s)",
399-
ex.getMessage(),
400-
nextEntry.getName(),
401-
jf.getName()));
402-
}
403-
nextEntry = nextEntry();
404-
}
405-
return false;
406-
}
407-
408-
public ClassModel next() {
409-
if (!hasNext()) {
410-
throw new NoSuchElementException();
411-
}
412-
ClassModel classFile = cf;
413-
cf = null;
414-
nextEntry = nextEntry();
415-
return classFile;
416-
}
417-
418-
protected JarEntry nextEntry() {
419-
while (entries.hasNext()) {
420-
JarEntry e = entries.next();
421-
String name = e.getName();
422-
if (name.endsWith(".class")) {
423-
return e;
424-
}
425-
}
426-
return null;
427-
}
428-
429-
public void remove() {
430-
throw new UnsupportedOperationException("Not supported yet.");
320+
@Override
321+
public void forEachClassFile(Consumer<ClassModel> handler) throws IOException {
322+
jarfile.versionedStream()
323+
.filter(JarFileReader::isJarEntryClass)
324+
.forEach(e -> {
325+
try {
326+
handler.accept(readClassFile(jarfile, e));
327+
} catch (ClassFileError | IOException ex) {
328+
skipEntry(ex, e.getName() + " (" + jarfile.getName() + ")");
329+
}
330+
});
431331
}
432332
}
433333
}

src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public static class ClassFileError extends Error {
7979
private static final long serialVersionUID = 4111110813961313203L;
8080

8181
public ClassFileError(Throwable cause) {
82-
initCause(cause);
82+
super(cause.getMessage(), cause);
8383
}
8484
}
8585

src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -173,9 +173,9 @@ private Optional<FutureTask<Set<Location>>> parse(Archive archive, Finder finder
173173
trace("parsing %s %s%n", archive.getName(), archive.getPathName());
174174
FutureTask<Set<Location>> task = new FutureTask<>(() -> {
175175
Set<Location> targets = new HashSet<>();
176-
for (var cf : archive.reader().getClassFiles()) {
176+
archive.reader().forEachClassFile(cf -> {
177177
if (cf.isModuleInfo())
178-
continue;
178+
return;
179179

180180
String classFileName;
181181
try {
@@ -187,11 +187,11 @@ private Optional<FutureTask<Set<Location>>> parse(Archive archive, Finder finder
187187
// filter source class/archive
188188
String cn = classFileName.replace('/', '.');
189189
if (!finder.accept(archive, cn, cf.flags()))
190-
continue;
190+
return;
191191

192192
// tests if this class matches the -include
193193
if (!filter.matches(cn))
194-
continue;
194+
return;
195195

196196
for (Dependency d : finder.findDependencies(cf)) {
197197
if (filter.accepts(d)) {
@@ -203,7 +203,7 @@ private Optional<FutureTask<Set<Location>>> parse(Archive archive, Finder finder
203203
}
204204
parsedClasses.putIfAbsent(d.getOrigin(), archive);
205205
}
206-
}
206+
});
207207
return targets;
208208
});
209209
tasks.add(task);

0 commit comments

Comments
 (0)