Skip to content

Bump io.github.classgraph:classgraph from 4.8.192 to 4.8.193 - #854

Merged
jonesbusy merged 1 commit into
mainfrom
dependabot/maven/io.github.classgraph-classgraph-4.8.193
Aug 24, 2026
Merged

Bump io.github.classgraph:classgraph from 4.8.192 to 4.8.193#854
jonesbusy merged 1 commit into
mainfrom
dependabot/maven/io.github.classgraph-classgraph-4.8.193

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Aug 24, 2026

Copy link
Copy Markdown
Contributor

Bumps io.github.classgraph:classgraph from 4.8.192 to 4.8.193.

Release notes

Sourced from io.github.classgraph:classgraph's releases.

ClassGraph 4.8.193

ClassGraph 5.0.0 is coming shortly, and requires JDK 17 or newer. 4.8.193 is a bugfix release on the 4.x maintenance branch, and continues the file-by-file audit of the codebase that produced 4.8.190 through 4.8.192. As before, the bugs listed here were found by Claude through careful code analysis, and were fixed on the v5 branch and backported to v4.

The largest group this time came from an audit of what a scan holds open and when it lets go of it: memory mappings, file handles, streams and pooled objects.

Bug fixes: memory mapping

  • Closing a ScanResult could unmap a file while another thread was still reading it, killing the JVM. FileSlice#close() unmapped the file the slice was reading, but aliases of that mapping escape three ways: a RandomAccessByteBufferReader keeps a duplicate for the life of the reader, FileSlice#read() hands a slice of the mapping to the caller, and a sub-slice duplicated it. Below JDK 22 the only way to unmap on demand is Unsafe::invokeCleaner, which frees the address range immediately and unconditionally, so a thread that read one byte afterwards took a SIGSEGV. A sub-slice now reads through the toplevel slice instead of duplicating the mapping, a reader taken before the close is given the slice's closed flag to check before each read, and a file is unmapped only once the toplevel slice has closed and every view of the mapping that a caller could still read has been released.

  • A memory-mapped jarfile stayed mapped after the scan that mapped it was closed. Below JDK 22 there is no arena, so closing a ScanResult merely dropped the last reference to each mapping and left the unmapping to the garbage collector — which might do it minutes later, or never. Windows refuses to delete, rename or overwrite a file while it is mapped, so a scanned jar stayed locked long after the ScanResult was closed, an extracted temporary file was left behind, and a scanned directory could not be deleted. Mappings are now unmapped explicitly when the scan closes, on every JDK: with the arena on JDK 22 and later, with Unsafe::invokeCleaner on JDK 9 to 21, and with sun.misc.Cleaner below JDK 9. The garbage collector is now only the fallback, for a mapping that could not be unmapped explicitly.

  • A closed resource stream went on holding its reader, and a reader of a memory-mapped file holds a view of the mapping, so the file stayed mapped for as long as anything still referred to the stream. The stream now drops its reader as it closes.

  • enableMemoryMapping() still maps on every JDK. The obvious way to close the crash above would have been to stop mapping below JDK 22, where the unmapping cannot be made safe by the arena — but that would have given up the mapping speedup (16-38% faster than the RandomAccessFile API on Windows) on every release but the newest. Ordering the unmapping behind the last live view of the mapping makes it safe without that, so mapping still happens wherever it is asked for.

Bug fixes: resource and scan lifecycle

  • A failed scan leaked every file handle, memory mapping and module reader it had opened. On the failure path the NestedJarHandler was closed only when there was no FailureHandler, or when the FailureHandler itself threw; a FailureHandler that returned normally fell through to a step that deletes temporary files but closes nothing. Three sibling leaks were fixed with it: the Scanner constructor released the handler only on InterruptedException, so a throwing classpath element filter leaked the whole handler with no way for the caller to reach it; a ScanResultProcessor that threw an Error — which is what a failing assertion inside one throws — skipped both close() calls, and nothing else can close that ScanResult; and a ScanResult that was garbage collected without being closed left a dead WeakReference husk in a static set forever, so the set grew without limit in a program that scans repeatedly without closing.

  • A resource that could not be opened was left marked as open. Resource#checkCanOpen set the open flag before checking whether the ScanResult had been closed, so every later attempt to open that resource reported "Resource is already open" instead of the real reason it could not be opened.

  • Handing a pooled object back after a ScanResult was closed either threw or leaked. Closing a ScanResult force-closes the inflater and module-reader recyclers, but a recycler kept no memory of that: it drained the pool and left recycle() free to add instances back in. An instance handed back afterwards was either rejected outright — with "Tried to recycle an instance that was not in use" thrown out of the close() that was handing it back — or, if it had been acquired after the force-close, pooled into a recycler that nothing would ever drain again, leaking the Inflater or ModuleReader it held. Closing a resource stream after closing the ScanResult reaches the first case. A force-close is now terminal.

Bug fixes: zipfile reading

  • A zipfile comment containing the bytes PK\x05\x06 made the jarfile unreadable. The end of central directory record is found by scanning back from the end of the file for that signature, and the record's comment length field was never checked against the bytes actually present, so the first plausible-looking signature found was accepted as the real record. The comment length now has to account for the remaining bytes exactly, and the scan continues to an earlier candidate if it does not. (Zipfiles do exist with data appended after the comment, or with the wrong comment length recorded, so if no candidate satisfies the check the last signature found is still used, as before.)

  • A jarfile whose entry names had been lower-cased was read as having no manifest at all, which silently dropped its Class-Path, its Bundle-ClassPath and everything else the manifest says. java.util.zip.ZipFile finds that manifest, because it matches META-INF/ and MANIFEST.MF a character at a time with the case bit masked off. The manifest is now looked for under its canonical name first, and only then under a name that differs from it in case alone.

  • A classfile named Foo.CLASS aborted the entire scan. JarUtils.classfilePathToClassName threw for a path whose extension was not exactly .class, even though such a file declares the same class at the same position in the directory tree and can be read like any other. Every "is this a classfile" test now goes through one case-insensitive predicate. module-info.class and package-info.class stay case-sensitive, since the JLS and the JPMS mandate those exact names.

Bug fixes: nested jar paths and classpath URLs

  • The nested jar separator is now spelled !/ everywhere, as the jar: URL scheme requires. sun.net.www.protocol.jar.Handler looks for the first ! that is immediately followed by /, and java.net.JarURLConnection rejects a URL whose ! is not followed by / while the URL is being constructed. ClassGraph found the outermost separator by testing the filesystem and then took every later ! to be a separator too — but ! is a legal character in a file or entry name, so outer.jar!/dir!name was split inside dir!name, and normalizing outer.jar!/dir!name/x.txt produced a URL naming an entry that does not exist. Which ! characters separate is now decided by how the outermost one is spelled, and JarUtils#toJarUrlSeparators is the single place a looser path is rewritten into the scheme's form.

  • A relative path that looks like a URL was misread as one. : is a legal filename character on every platform ClassGraph supports except Windows, and a relative path need not begin with /, so foo:bar is spelled exactly like a URL whose scheme is foo. The syntactic rule is now applied only after the filesystem has been asked, so cgtest:relpath/dir!name/y.jar is no longer split at the ! while reldir/dir!name/y.jar — the same path but for the colon — is correctly left alone.

  • A URL scheme containing a digit was not recognized when ordering the classpath, even though RFC 3986 allows digits after the first character.

  • The same resource reached under two spellings was scanned twice. Two of these: a scheme that is merely kept rather than recognized by name, such as S3://bucket/key, was passed through in whatever case it was written in, rather than lowercased to its canonical form; and the key that decides whether two resources are the same file canonicalized only the directory the file is in, keeping the name it was reached by, so a jar reached through a symlink was a different file from the jar itself, and on a case-folding filesystem a jar named with a different case was a different file too — which on macOS and Windows the module path and the classpath routinely produce.

  • 18 of the 20 ClassLoaderHandler registry entries had null cached for their package root prefixes. The registry entries are built by a static initializer that runs before the prefix constants declared further down the same class are assigned, and the entry read the prefixes in its constructor. The entry now forwards to the handler rather than caching, so it reads the constants after they are assigned. Fifteen of the affected handlers were unaffected in practice, since null is replaced by the defaults; the other three returned "no package root prefixes", and none of the three justified suppressing package roots — the JPMS handler in particular contributes the jarfiles a Java agent appended to the system classloader's search, which are not modules, so a Spring Boot jar appended that way needs its package root stripped like any other.

  • A failure to parse or convert a jar URL discarded the underlying cause, so the exception said what had failed but not why.

Bug fixes: interruption handling

  • Interrupting a scan could leave it running to completion, returning a ScanResult that was silently missing a classpath element. The catch-all that turns a failed classpath entry into a log line and moves on also caught InterruptedException — and that exception arrives with the interrupt status already cleared when it comes out of waiting for a classpath element another work unit is already opening, so nothing downstream noticed either.

  • A cancelled scan was reported as a failed one. Future.get() wraps an InterruptedException thrown by a worker in an ExecutionException like any other, and both places that catch that handed it straight to the "record an exception" path, which is checked ahead of the interruption check. It also cost a genuine failure its report, since only the first exception is kept. An interrupted worker is now recorded as an interruption.

... (truncated)

Commits
  • f7b9842 [maven-release-plugin] prepare release classgraph-4.8.193
  • 440849f Look up java.lang.System by its fully-qualified name
  • 0820e6e Update Narcissus to 1.0.12
  • 495a957 Make both reflection drivers agree on static and non-static members
  • e5b9998 Check for this test's remapped URL rather than assuming it is the only one
  • 00efbbd Accept digits in a URL scheme when ordering the classpath
  • 06c1658 Correct the pre-commit hook's note on why it formats the whole tree
  • 3fd0dd2 Reformat a staged rename too, not just an added or modified file
  • 23b9b61 Fix the pre-commit hook
  • dfc15e4 Check the test sources with doclint too, minus the "missing" group
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [io.github.classgraph:classgraph](https://github.com/classgraph/classgraph) from 4.8.192 to 4.8.193.
- [Release notes](https://github.com/classgraph/classgraph/releases)
- [Commits](classgraph/classgraph@classgraph-4.8.192...classgraph-4.8.193)

---
updated-dependencies:
- dependency-name: io.github.classgraph:classgraph
  dependency-version: 4.8.193
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file java Pull requests that update Java code labels Aug 24, 2026
@dependabot
dependabot Bot requested a review from jonesbusy as a code owner August 24, 2026 05:20
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file java Pull requests that update Java code labels Aug 24, 2026
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.57%. Comparing base (950f138) to head (0a13e30).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff              @@
##               main     #854      +/-   ##
============================================
+ Coverage     87.16%   87.57%   +0.41%     
  Complexity     1281     1281              
============================================
  Files            51       51              
  Lines          4114     4114              
  Branches        565      565              
============================================
+ Hits           3586     3603      +17     
+ Misses          310      293      -17     
  Partials        218      218              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@jonesbusy
jonesbusy merged commit 049e64c into main Aug 24, 2026
11 checks passed
@jonesbusy
jonesbusy deleted the dependabot/maven/io.github.classgraph-classgraph-4.8.193 branch August 24, 2026 06:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file java Pull requests that update Java code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant