On Fri, 11 Apr 2025 22:45:55 GMT, Chen Liang <[email protected]> wrote:
> When jdeps was migrated from old classfile to ClassFile API, the parsing
> semantic changed - error checks are now made lazily, and nested crashes from
> malformed signature or other problems is now latent, after a `ClassModel`
> instance is available. (The old error check existed only for constructing a
> `ClassModel`)
>
> To address this issue, I have updated the way of iterating class files to be
> handler/consumer based like in the ClassFile API. This has the advantage that
> when one invocation of the handler fails of a `ClassFileError`, other
> invocations for other class files can proceed, and the exception handler has
> sufficient information to report a useful message indicating the source of
> error.
>
> For the particular example of examining a proguard processed
> `dummy-scala.jar`, here is the new output of `jdeps dummy-scala.jar`:
>
> Warning: com.sun.tools.jdeps.Dependencies$ClassFileError: Unexpected
> character ; at position 59, expected an identifier:
> Lscala/collection/immutable/TreeMap$TreeMapBuilder<TA;TB;>.;:
> scala/collection/immutable/TreeMap$TreeMapBuilder.class (dummy-scala.jar)
> Warning: com.sun.tools.jdeps.Dependencies$ClassFileError: Unexpected
> character ; at position 49, expected an identifier:
> Lscala/collection/parallel/mutable/ParArray<TT;>.;:
> scala/collection/parallel/mutable/ParArray.class (dummy-scala.jar)
>
>
> Now, jdeps shows the bad class files. Inspection into the files reveal that
> proguard incorrectly deleted the simple class names with trailing `$`, for
> example, the original signature of the broken ParArray was
> `Lscala/collection/parallel/mutable/ParArray<TT;>.ParArrayIterator$;`, so the
> `ParArrayIterator$` part was incorrectly dropped by proguard.
>
> Testing: langtools/tools/jdeps.
src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java line 105:
> 103:
> 104: protected void skipEntry(ClassFileError ex, String fileName) {
> 105: skippedEntries.add(String.format("%s: %s", ex.toString(),
> fileName));
The second parameter is not always a straightforward filename, consider to
rename it, perhaps `entryPath`?
src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java line 237:
> 235: skipEntry(ex, e.toString());
> 236: } catch (IOException ex) {
> 237: throw new UncheckedIOException(ex);
Just to point out this was leading to ClassFileError in the old implementation,
new implementation will relay the IOException, which I think is proper.
src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java line 339:
> 337: });
> 338: } catch (UncheckedIOException ex) {
> 339: throw ex.getCause();
IOException used to skip entry with message and continue, the new behavior
would change. I am not certain this is behavior compatible.
I doubt IOException would be recoverable on different entry, but it might in
rare cases?
src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java line 176:
> 174: FutureTask<Set<Location>> task = new FutureTask<>(() -> {
> 175: Set<Location> targets = new HashSet<>();
> 176: archive.reader().processClassFiles(cf -> {
I prefer the naming convention with forEach for operation to iterate through
rather than have a `process` on a reader. Perhaps named like `forEachClassFile`?
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/24604#discussion_r2049319406
PR Review Comment: https://git.openjdk.org/jdk/pull/24604#discussion_r2049411874
PR Review Comment: https://git.openjdk.org/jdk/pull/24604#discussion_r2049425413
PR Review Comment: https://git.openjdk.org/jdk/pull/24604#discussion_r2049378312