Skip to content

Fix deadlock in AbstractRequestCache.requests() due to unstable hashCode#12166

Open
gnodet wants to merge 1 commit into
maven-4.0.xfrom
fix/identity-hashmap-request-cache
Open

Fix deadlock in AbstractRequestCache.requests() due to unstable hashCode#12166
gnodet wants to merge 1 commit into
maven-4.0.xfrom
fix/identity-hashmap-request-cache

Conversation

@gnodet
Copy link
Copy Markdown
Contributor

@gnodet gnodet commented May 27, 2026

Summary

  • Fix a deadlock in AbstractRequestCache.requests() caused by request objects with unstable hashCode(), by switching the internal coordination map from HashMap to IdentityHashMap

Root Cause

The requests() method uses a local HashMap<REQ, Object> (nonCachedResults) to coordinate batch resolution results. The batch supplier puts resolved results into this map, and the individualSupplier lambda retrieves them via containsKey().

The problem: ResolverRequest is a Java record whose hashCode() transitively includes RequestTrace.data, which holds a ModelBuilderRequest containing mutable systemProperties. During artifact resolution, these properties can change, causing the same object to produce different hash values at put() time vs containsKey() time. The entry is stored in one hash bucket but looked up in another — containsKey() returns false, and the thread waits forever on a result that is already in the map.

Debug evidence (same object reference, three different hashes at different times):

setup:              id=836903781 hash=-1162624231
batch put:          id=836903781 hash=-814242078
individualSupplier: id=836903781 hash=513211466  sameRef=true  equals=true

Fix

Switch from HashMap to IdentityHashMap, which uses System.identityHashCode() (stable, based on object identity) and == for equality. Since the code always operates on the same object references for put and get (confirmed by sameRef=true), this is safe and correct.

Impact

This fixes the ~80 timeout failures observed in Maven 4 compatibility testing where Maven 4 hangs indefinitely on projects using maven-remote-resources-plugin. The hang occurs during parent POM resolution triggered by the plugin's getProjects() call, when the model builder's request trace mutates system properties mid-resolution.

Test plan

  • Reproduced locally: httpcomponents-stylecheck hangs indefinitely with Maven 4 + mvnup (adds maven-remote-resources-plugin:3.0.0)
  • Verified fix: same project builds in 1.6s after the change
  • Maven's own build (mvn verify -DskipTests) passes with the fix

Claude Code on behalf of Guillaume Nodet

The `requests()` method uses a HashMap to coordinate batch results between
the batch supplier and the individual CachingSupplier instances. When a
request object's hashCode() changes between HashMap.put() and
HashMap.containsKey() (e.g., because ResolverRequest includes a
RequestTrace with mutable ModelBuilderRequest data), the key is stored
in one bucket but looked up in another, causing containsKey() to return
false. The individualSupplier then waits forever for a result that is
already in the map but unreachable.

Switch to IdentityHashMap which uses System.identityHashCode() and
reference equality (==), both of which are stable regardless of
mutable object state. This is safe because the code always uses the
same object reference for put and get.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant