stevenschlansker opened a new issue, #1055:
URL: https://github.com/apache/maven-enforcer/issues/1055

   ### Affected version
   
   3.6.3, 3.6.2
   
   ### Bug description
   
   ### Versions
   
   Initially produced with maven-enforcer-plugin 3.6.2. `EnforcerRuleCache` and 
`EnforceMojo` are the same in 3.6.3 and on master.
   
   ### Symptom
   
   A multi-module build with `-T4C` failed in an `enforcer:enforce` execution:
   
   ```
   Caused by: java.util.ConcurrentModificationException
       at java.util.HashMap.computeIfAbsent (HashMap.java:1255)
       at org.apache.maven.plugins.enforcer.internal.EnforcerRuleCache.isCached 
(EnforcerRuleCache.java:81)
       at org.apache.maven.plugins.enforcer.EnforceMojo.executeRuleNew 
(EnforceMojo.java:350)
       at org.apache.maven.plugins.enforcer.EnforceMojo.executeRule 
(EnforceMojo.java:325)
       at org.apache.maven.plugins.enforcer.EnforceMojo.execute 
(EnforceMojo.java:249)
   ```
   
   ### Cause
   
   `isCached` locks `synchronized (this)` and then reads and writes a plain 
`HashMap`. The map is in the repository session data under the key 
`enforcer-cache`. Thus the lock belongs to the `EnforcerRuleCache` instance, 
but the map belongs to the session.
   
   Maven creates a separate plugin realm for each different set of plugin 
dependencies, and each realm has its own `@Singleton` `EnforcerRuleCache`. In a 
reactor with two realms, two instances lock different monitors and write the 
same map. `HashMap.computeIfAbsent` sees the concurrent write and throws. The 
unlocked `sessionData.get` and `sessionData.set` pair has the same race: two 
instances can each create a map, and the second map replaces the first.
   
   Modules in our reactor can inherit two versions of our parent POM. The two 
enforcer plugin declarations are the same except for the `extra-enforcer-rules` 
plugin dependency (1.12.0 and 1.12.1). We did not confirm the number of realms 
in the failed run. With one realm, the lock covers every access to the map.
   
   ### Conditions
   
   - A reactor build with `-T` greater than 1.
   - Two or more modules that give `maven-enforcer-plugin` different plugin 
`<dependencies>`, so that Maven loads more than one plugin realm.
   - Rules that return a non-null `getCacheId()`.
   
   We do not have a minimal reproducer yet.
   
   ### Suggested fix
   
   Synchronize on the `SessionData` instance, not on `this`. All realms in one 
build get the same `SessionData`, and this works on Maven versions before 3.9. 
On Maven 3.9 and later, `SessionData.computeIfAbsent` with a 
`ConcurrentHashMap` is an alternative.
   
   ### Workaround
   
   `-Denforcer.ignoreCache=true` skips `isCached` (`EnforceMojo.java:350`).
   


-- 
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]

Reply via email to