gnodet-bot commented on code in PR #13570:
URL: https://github.com/apache/maven/pull/13570#discussion_r4322865567


##########
impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java:
##########
@@ -79,7 +80,9 @@ public Optional<Type> lookup(String id) {
     public Type require(String id) {
         requireNonNull(id, "id cannot be null");
         return usedTypes.computeIfAbsent(id, i -> {
+            ClassLoader tccl = Thread.currentThread().getContextClassLoader();
             Type type = lookup.lookupList(TypeProvider.class).stream()
+                    .filter(p -> ExtensibleEnumRegistries.isVisibleFrom(p, 
tccl))

Review Comment:
   ⚠️ **Caching defeats the classloader filter.** `computeIfAbsent(id, i -> { 
... })` runs the lambda — including the TCCL capture and `isVisibleFrom` filter 
— only on the *first* lookup of a given `id`. All subsequent calls return the 
cached `Type` without re-checking the calling thread's classloader. In a 
parallel reactor build, module A's first lookup caches the result, and module 
B's lookup of the same id reuses that cached value even if the provider is not 
visible from module B's classloader.
   
   The filter must be moved outside `computeIfAbsent`, to the call site that 
needs per-call TCCL semantics. The `usedTypes` cache was designed to avoid 
repeated SPI enumeration — but it conflates two things: caching the *provider 
lookup* and caching the *visibility decision*. The latter must be per-call.



##########
impl/maven-impl/src/main/java/org/apache/maven/impl/ExtensibleEnumRegistries.java:
##########
@@ -89,15 +152,57 @@ public abstract static class DefaultExtensibleEnumRegistry<
             implements ExtensibleEnumRegistry<T> {
 
         protected final Map<String, T> values;
+        private final Lookup lookup;
+        private final Class<P> providerType;
 
+        @SafeVarargs
         public DefaultExtensibleEnumRegistry(List<P> providers, T... 
builtinValues) {
+            this(null, null, providers, builtinValues);
+        }
+
+        @SafeVarargs
+        public DefaultExtensibleEnumRegistry(
+                Lookup lookup, Class<P> providerType, List<P> providers, T... 
builtinValues) {
+            this.lookup = lookup;
+            this.providerType = providerType;

Review Comment:
   ⚠️ **4-arg constructor is unused in production.** The three concrete inner 
subclasses (`DefaultPathScopeRegistry`, `DefaultProjectScopeRegistry`, 
`DefaultLanguageRegistry`) all delegate to the 2-arg constructor 
(`super(providers, builtinValues)`), which sets `lookup = null` and 
`providerType = null`. The `if (lookup != null && providerType != null)` branch 
in `lookup()` therefore never executes in production — only the test uses the 
4-arg path.
   
   Either wire the `Lookup` through DI for these subclasses (so the fix 
actually takes effect), or remove the dead code path and document explicitly 
that the reactor-leak fix is limited to `DefaultTypeRegistry.require()` only.



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