You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/05/28 21:15:50 UTC
(maven) branch maven-4.0.x-test-fixes updated: Fix re-entrant self-deadlock in CachingSupplier (PR #12166)
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch maven-4.0.x-test-fixes
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/maven-4.0.x-test-fixes by this push:
new 0ee8ce1f5d Fix re-entrant self-deadlock in CachingSupplier (PR #12166)
0ee8ce1f5d is described below
commit 0ee8ce1f5d53a8728a4e201beb6c0f47ebf00060
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu May 28 23:15:41 2026 +0200
Fix re-entrant self-deadlock in CachingSupplier (PR #12166)
Cherry-pick from fix/identity-hashmap-request-cache branch.
When requests() stores CachingSuppliers wrapping individualSupplier in
the session cache, a re-entrant call from the same thread self-deadlocks.
Track the computing thread and fall back to direct computation on
re-entrant access.
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
.../maven/impl/cache/AbstractRequestCache.java | 9 ++++++++-
.../org/apache/maven/impl/cache/CachingSupplier.java | 20 ++++++++++++++++++++
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/AbstractRequestCache.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/AbstractRequestCache.java
index 0dc5a7d0f0..4d655c7620 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/AbstractRequestCache.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/AbstractRequestCache.java
@@ -60,7 +60,14 @@ public abstract class AbstractRequestCache implements RequestCache {
@SuppressWarnings("all")
public <REQ extends Request<?>, REP extends Result<REQ>> REP request(REQ req, Function<REQ, REP> supplier) {
CachingSupplier<REQ, REP> cs = doCache(req, supplier);
- return cs.apply(req);
+ try {
+ return cs.apply(req);
+ } catch (CachingSupplier.CyclicCacheAccessException e) {
+ // Re-entrant access from the same thread (e.g., a batch requests() computation
+ // triggered a singular request() that found the same cached entry). Compute
+ // directly with the caller's supplier to break the cycle.
+ return supplier.apply(req);
+ }
}
/**
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/CachingSupplier.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/CachingSupplier.java
index d1960b1944..85b2411e01 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/CachingSupplier.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/CachingSupplier.java
@@ -30,6 +30,8 @@
public class CachingSupplier<REQ, REP> implements Function<REQ, REP> {
protected final Function<REQ, REP> supplier;
protected volatile Object value;
+ // Guarded by synchronized(this) — tracks which thread is currently computing
+ private Thread computingThread;
public CachingSupplier(Function<REQ, REP> supplier) {
this.supplier = supplier;
@@ -46,10 +48,18 @@ public REP apply(REQ req) {
if ((v = value) == null) {
synchronized (this) {
if ((v = value) == null) {
+ if (computingThread == Thread.currentThread()) {
+ throw new CyclicCacheAccessException();
+ }
+ computingThread = Thread.currentThread();
try {
v = value = supplier.apply(req);
+ } catch (CyclicCacheAccessException e) {
+ throw e;
} catch (Exception e) {
v = value = new AltRes(e);
+ } finally {
+ computingThread = null;
}
}
}
@@ -60,6 +70,16 @@ public REP apply(REQ req) {
return (REP) v;
}
+ /**
+ * Thrown when a re-entrant call is detected on the same thread that is already
+ * computing this supplier's value. Prevents self-deadlock when a batch
+ * {@code requests()} computation triggers a singular {@code request()} that
+ * finds the same CachingSupplier in the cache.
+ */
+ public static class CyclicCacheAccessException extends RuntimeException {
+ CyclicCacheAccessException() {}
+ }
+
/**
* Special holder class for exceptions that occur during supplier execution.
* Allows caching and re-throwing of exceptions on subsequent calls.