dependabot[bot] opened a new pull request, #26419: URL: https://github.com/apache/camel/pull/26419
Bumps [io.github.classgraph:classgraph](https://github.com/classgraph/classgraph) from 4.8.194 to 4.8.195. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/classgraph/classgraph/releases">io.github.classgraph:classgraph's releases</a>.</em></p> <blockquote> <h2>ClassGraph 4.8.195</h2> <p><strong>ClassGraph 5.0.0 is coming shortly</strong>, and requires JDK 17 or newer. 4.8.195 is a bugfix release on the 4.x maintenance branch, and continues the file-by-file audit that produced 4.8.190 through 4.8.194. As before, most of the bugs listed here were found by Claude through careful code analysis, and were fixed on the v5 branch and backported to v4.</p> <p>The themes this time are a scan that can never finish, temporary files that were left behind or misnamed, classpath entries that were silently dropped, and a set of correctness fixes in the class graph itself.</p> <h2>New API</h2> <ul> <li><strong><code>ClassGraph#setWorkerTimeout(long, TimeUnit)</code>.</strong> Every <code>Future#get()</code> call in the scanner now has a timeout, so a scan that can never finish reports why instead of hanging. The two known causes are the classloading deadlock of <a href="https://redirect.github.com/classgraph/classgraph/issues/933">#933</a>, and a worker thread blocking on a filesystem or network read of a classpath element — a stalled HTTP server serving a remote jarfile, for instance. <strong>The timeout defaults to one minute</strong>, so a scan that previously blocked forever now fails with an exception naming the reason. A timeout of zero or less waits indefinitely, which is the previous behavior.</li> </ul> <h2>Bug fixes: scans that never return</h2> <ul> <li> <p><strong>The call stack and the context classloader were read on a worker thread during <code>scanAsync()</code>.</strong> The <code>Scanner</code> was constructed inside the task submitted to the <code>ExecutorService</code>, so the call stack that ClassGraph reads to find classloaders, and the thread context classloader it uses, were those of a pool thread rather than of the caller. They are now read on the calling thread, before anything is submitted.</p> </li> <li> <p><strong>The <a href="https://redirect.github.com/classgraph/classgraph/issues/933">#933</a> fallback now works on Java 8, and covers a classloader as well as a static initializer.</strong> If the calling thread holds a class loading lock, loading a class on a worker thread deadlocks the scan, so the whole scan is run on the calling thread whatever number of threads was requested, and the frame holding the lock is named in the verbose log. Where <code>StackWalker</code> is not available, the classes declaring the stack frames are taken from the call stack that was already read, so a frame can be matched to its class without loading anything — which is what must not be done while a class loading lock is held.</p> </li> </ul> <h2>Bug fixes: temporary files</h2> <ul> <li> <p><strong>A jarfile whose name contains <code>---</code> was scanned under a truncated name.</strong> ClassGraph names the files it extracts <code>ClassGraph--<random>---<name></code>, and <code>leafName()</code> treated <code>---</code> anywhere in a path as that separator. A jarfile genuinely named <code>x---y.jar</code> was therefore reported as <code>y.jar</code>, and that truncated name is what accept and reject criteria are matched against. Worse, a <code>---</code> in a path <em>inside</em> a jarfile falls after the end of the leafname, so the leafname came back empty and the jar matched no criterion at all and was silently skipped. The separator is now only honored in a leafname that starts with <code>ClassGraph--</code>, and only at the first separator after that prefix.</p> </li> <li> <p><strong>A temporary file that was still memory mapped at the end of a scan was left on disk for the life of the JVM.</strong> Below JDK 22 a mapping is dropped by freeing its address range, which cannot be done while the caller can still read a buffer of it, so a file held open by such a view stays mapped after the scan closes. Windows refuses to delete a mapped file, and the retry that closing the scan makes after asking for a garbage collection cannot help either, since the buffer the caller holds is strongly reachable. The file is now deleted when the last view of its mapping is released, rather than being left to the <code>deleteOnExit()</code> hook.</p> </li> <li> <p><strong>A slice or an arena that would not close was not reported.</strong> An <code>IOException</code> from a slice that would not close was dropped silently, so a file handle or a mapping that outlived a scan left nothing in the log to explain why a jarfile could not afterwards be deleted or overwritten on Windows; an unchecked failure was not caught at all, and abandoned the rest of the teardown — the slices still to be closed, the inflater recycler, and the temporary files. On JDK 22 and later, an arena that fails to close leaves its file mapped, and that too went unrecorded, so no collection was asked for before the temporary files were deleted.</p> </li> <li> <p><strong>Scanning an exploded module leaked an open directory for the life of the JVM.</strong> <code>ModuleReader#list()</code> returns a stream that walks the module's directory tree, and closing that stream is what closes the directories the walk opened. It was collected into a list and dropped without being closed.</p> </li> </ul> <h2>Bug fixes: classpath elements that were dropped or duplicated</h2> <ul> <li> <p><strong>A nested classpath element was missed when a sibling sorted between it and its parent.</strong> <code>findNestedClasspathElements()</code> sorts the classpath elements and walks forward from each looking for elements nested within it, stopping at the first element that is not nested. Every character below <code>/</code> sorts before it, so for the base path <code>/a/classes</code> the sibling <code>/a/classes-extra</code> falls between it and <code>/a/classes/sub</code>: the walk stopped at the sibling, the outer element no longer masked the nested one, and the nested element's resources were reported twice.</p> </li> <li> <p><strong>A package root or nested jarfile that exists only under a version prefix could not be found.</strong> An entry stored under <code>META-INF/versions/N/</code> in a multi-release jarfile is served without that prefix, and the base copy it masks is gone from the entry list, so a lookup by the stored name matched nothing: naming <code>app.jar!/WEB-INF/classes</code> on the classpath failed with "Path WEB-INF/classes does not exist in jarfile", and the package root of a war or Spring Boot jar whose classes are versioned was dropped.</p> </li> <li> <p><strong>Version prefixes were resolved in a jarfile that is not multi-release.</strong> A jarfile is only multi-release if its manifest carries the <code>Multi-Release</code> key; in one that does not, the JVM reads an entry under <code>META-INF/versions/</code> from the path it is stored under. The prefix was being stripped from every entry as the central directory was read, which is before the manifest has been parsed, so a "versioned" entry masked the base entry of the same path — the scan reported the versioned entry's content under the base entry's path, and did not report the base entry at all.</p> </li> <li> <p><strong>A classpath entry whose path a URI cannot hold was dropped entirely.</strong> When stripping a package root suffix from a URI or URL entry, the resolved path — which is percent-decoded — was parsed back as a URI, and the entry was discarded when neither the bare path nor the <code>file:</code> spelling parsed. A path containing a space took that branch, as did any Windows path, since a backslash is illegal in a URI. It now degrades to the path string, as the <code>File</code> branch already did.</p> </li> <li> <p><strong>A URL that was already percent-encoded was encoded a second time.</strong> <code>normalizeURLPath</code> left an <code>http:</code>, <code>https:</code> or <code>jrt:</code> URL alone and then passed it to the encoder written for decoded file paths, so <code>%20</code> became <code>%2520</code>, the colon before a port number became <code>%3a</code>, and a query string <code>?v=1&t=2</code> became <code>%3fv%3d1%26t%3d2</code> — after which <code>URI#getHost</code> returned null and <code>URI#getPort</code> returned -1, matching nothing that ClassGraph actually fetches. Such a URL is now escaped by a rule that leaves an existing escape alone and encodes only what a URI cannot hold. File paths are unchanged.</p> </li> </ul> <h2>Bug fixes: classloader order</h2> <ul> <li> <p><strong>A classloader appeared in the delegation order once per handler that could handle it.</strong> More than one <code>ClassLoaderHandler</code> can handle the same classloader — one that a handler recognizes by name may also extend <code>URLClassLoader</code> — and each is asked for the entries it knows how to read, but the classloader itself was added to the order each time.</p> </li> <li> <p><strong>Two classloaders that claim to be equal collapsed into one.</strong> <code>findDefaultClassLoaders()</code> collected classloaders in a <code>LinkedHashSet</code>, so the classes of the one that was dropped were never scanned. Separately, <code>ClassLoaderOrder</code> deduplicated by identity, as it must, but then kept the order in a map keyed by classloader: adding the second of two equal classloaders replaced the handlers of the first rather than appending, so one of the two dropped out of the order and its entries were never found, and the one left behind ran the other one's handlers. This is not hypothetical — TomEE makes an instance of <code>CxfContainerClassLoader</code> equal to the <code>TomEEWebappClassLoader</code> it delegates to (<a href="https://redirect.github.com/classgraph/classgraph/issues/515">#515</a>).</p> </li> </ul> <h2>Bug fixes: zipfile and classfile reading</h2> <ul> <li> <p><strong>An MS-DOS zip timestamp was read in the default locale's calendar system.</strong> The year, month and day of an MS-DOS date are Gregorian, but the conversion built a calendar for the default locale, so under <code>th-TH-u-ca-buddhist</code> or <code>ja-JP-u-ca-japanese</code> an entry timestamped September 2020 was reported as September 1477. Only an entry with no extended timestamp extra field is affected, which is what <code>ZipOutputStream</code> writes when <code>ZipEntry#setTime(long)</code> is the only time that was set.</p> </li> <li> <p><strong>A read into a <code>ByteBuffer</code> that carried a limit from a previous read threw <code>IllegalArgumentException</code>.</strong> A read leaves the buffer's limit where it stopped, so a later read starting further into the same buffer positioned past that stale limit — not one of the exceptions <code>InputStream.read(byte[], int, int)</code> is allowed to throw for a valid range. Three of the four readers already opened the limit before positioning; <code>ClassfileReader</code> did not, so the same call sequence failed or succeeded depending on where the content was being read from. The file-channel reader reuses one <code>ByteBuffer</code> across array reads, so array reads through it were affected too.</p> </li> <li> <p><strong>A stream of unknown length was read into a 64MB buffer.</strong> The buffer was allocated at <code>maxBufferedJarRAMSize</code> even for a stream holding a few bytes, and a stream whose length hint understated it was spilled to a temporary file rather than read into a larger buffer. The buffer now starts at the length hint, or 16kB when there is no usable hint, and doubles as it fills. A related fix: <code>InputStream#read</code> is allowed to return zero from a read of a non-empty buffer, and that was being treated as a full buffer, doubling the buffer on every such read until it reached the maximum or spilled to disk.</p> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/classgraph/classgraph/commit/dac837f40e158e861633e0440c194c70e5a96223"><code>dac837f</code></a> [maven-release-plugin] prepare release classgraph-4.8.195</li> <li><a href="https://github.com/classgraph/classgraph/commit/dc06d6c6711cfa39a1af42105108dfac5f46cddc"><code>dc06d6c</code></a> Assert the deferred temp file delete unconditionally</li> <li><a href="https://github.com/classgraph/classgraph/commit/fd2735a83e9fcd485ddf6fe77f36142cb9f6cdfc"><code>fd2735a</code></a> Run the deferred temporary file delete test on Windows too</li> <li><a href="https://github.com/classgraph/classgraph/commit/4b908317ff98c33fafbf25b2f10b36ee09f17c6f"><code>4b90831</code></a> Delete a temporary file whose delete had to wait for the file to be unmapped</li> <li><a href="https://github.com/classgraph/classgraph/commit/5688da69cc4705115b18d5a5970d26d77b327e13"><code>5688da6</code></a> Retry an interrupted SingletonMap creation instead of poisoning the key</li> <li><a href="https://github.com/classgraph/classgraph/commit/fdadbe263896672370fbb5d2e3fc931750769e85"><code>fdadbe2</code></a> Don't resolve version prefixes in a jar that is not multi-release</li> <li><a href="https://github.com/classgraph/classgraph/commit/b965f2c3316d26f1b21cfd10b8488ff2ec79cd22"><code>b965f2c</code></a> Find a nested classpath entry that exists only under a version prefix</li> <li><a href="https://github.com/classgraph/classgraph/commit/ad122a165bef4320c29c719392637718f01b9b73"><code>ad122a1</code></a> Never report a rejected resource from getResourcesWithPathIgnoringAccept</li> <li><a href="https://github.com/classgraph/classgraph/commit/30423edb0a4b1b46139fabd69392bbd460d813ae"><code>30423ed</code></a> Stop discarding the cause of an exception that is rethrown</li> <li><a href="https://github.com/classgraph/classgraph/commit/63cd5aa896e1c5c91d3110aaf33553d8101cb394"><code>63cd5aa</code></a> Stop percent-encoding a URL that is already percent-encoded</li> <li>Additional commits viewable in <a href="https://github.com/classgraph/classgraph/compare/classgraph-4.8.194...classgraph-4.8.195">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) 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-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> 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) </details> -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
