Fix inflater cache race in NestedJarFileResources

Update `NestedJarFileResources` to fix a race condition that could
result in a `NullPointerException`.

The methods `getOrCreateInflater` and `endOrCacheInflater` both
synchronize on a local `inflaterCache` variable but attempted to use the
`this.inflaterCache` instance which could be set to null.

The `releaseInflators` method had a synchronized block for ending each
inflater but the cache was being nulled out outside the block meaning that
the other 2 methods mentioned could hit the race condition.

Signed-off-by: Ian Kettle <25729118+icikle@users.noreply.github.com>

See gh-51744
This commit is contained in:
Ian Kettle
2026-09-14 17:34:45 -07:00
committed by Phillip Webb
parent b923033cb3
commit b103aaa1f6
@@ -116,7 +116,7 @@ class NestedJarFileResources implements Runnable {
Deque<Inflater> inflaterCache = this.inflaterCache;
if (inflaterCache != null) {
synchronized (inflaterCache) {
Inflater inflater = this.inflaterCache.poll();
Inflater inflater = inflaterCache.poll();
if (inflater != null) {
return inflater;
}
@@ -136,7 +136,7 @@ class NestedJarFileResources implements Runnable {
synchronized (inflaterCache) {
if (this.inflaterCache == inflaterCache && inflaterCache.size() < INFLATER_CACHE_LIMIT) {
inflater.reset();
this.inflaterCache.add(inflater);
inflaterCache.add(inflater);
return;
}
}
@@ -167,13 +167,13 @@ class NestedJarFileResources implements Runnable {
private IOException releaseInflators(IOException exceptionChain) {
Deque<Inflater> inflaterCache = this.inflaterCache;
if (inflaterCache != null) {
try {
synchronized (inflaterCache) {
synchronized (inflaterCache) {
try {
inflaterCache.forEach(Inflater::end);
}
}
finally {
this.inflaterCache = null;
finally {
this.inflaterCache = null;
}
}
}
return exceptionChain;