java-topology/defects/weld/patch/weld-0005-services-identify-service-interfaces-diamond.md
russell@unturf.com 130e4fb159 undf: assign 671-680 to diamond-scan defects; 680 total assigned
New defects from diamond O(2^D) sweep:
- cpython-0002/0003/0004: pydoc.allmethods, turtle.__methodDict, idlelib.rpc._getmethods
- micronaut-0005/0006/0007: populateTypeHierarchy, populateTypeArgumentsForInterfaces, SuperclassAwareTypeVisitor
- quarkus-0004/0005: HierarchyDiscovery.discoverTypes, ConfigMappingUtils.collectInterfacesRec
- weld-0004/0005: HierarchyDiscovery.discoverTypes, Services.identifyServiceInterfaces
- rails-0019: Digestor#dependency_digest Array#include? O(N²)
- spring-0007: AnnotationsScanner.processClassHierarchy O(2^D)
- django-0007: migrations.state.flatten_bases O(2^D)
- typescript-0005: hasBaseType O(2^D)
- hibernate-validator-0003: ClassHierarchyHelper.getImplementedInterfaces O(2^D)
- swift-0001: QualifiedLookupRequest::evaluate protocol superclass O(2^D)
2026-03-29 20:27:09 -04:00

4 KiB
Raw Permalink Blame History

UNDF: UNDF-2026-000000672

UNDF: (pending)

weld-0005: Services.identifyServiceInterfaces — O(2^D) diamond interface re-traversal

CWE-407 — Algorithmic Complexity: O(2^D) recursive diamond re-traversal in CDI service registry discovery

Field Value
ID weld-0005
Severity HIGH
Ecosystem weld
Package org.jboss.weld.util
File impl/src/main/java/org/jboss/weld/util/Services.java
Lines 5065
Complexity O(2^D) on diamond interface hierarchies
Hot path Weld CDI bootstrap — service registry population (startup)

Defect

public static Set<Class<? extends Service>> identifyServiceInterfaces(Class<?> clazz,
        Set<Class<? extends Service>> serviceInterfaces) {
    if (clazz == null || Object.class.equals(clazz) || BootstrapService.class.equals(clazz)) {
        return serviceInterfaces;
    }
    for (Class<?> interfac3 : clazz.getInterfaces()) {
        if (Service.class.equals(interfac3) || BootstrapService.class.equals(interfac3)) {
            serviceInterfaces.add(Reflections.cast(clazz));
        }
    }
    for (Class<?> interfac3 : clazz.getInterfaces()) {
        identifyServiceInterfaces(interfac3, serviceInterfaces);  // unconditional recursion
    }
    identifyServiceInterfaces(clazz.getSuperclass(), serviceInterfaces); // unconditional recursion
    return serviceInterfaces;
}

The method has no visited guard. serviceInterfaces accumulates results (classes that directly implement Service), but it is not used to guard traversal — an interface class I3 shared by two branches of a diamond hierarchy is passed to identifyServiceInterfaces twice per diamond level, giving O(2^D) recursive calls. The method iterates clazz.getInterfaces() twice (once for result collection, once for recursion), doubling the constant factor.

A custom BootstrapService implementation with a layered interface hierarchy (e.g., a monitoring service that extends multiple diagnostic interfaces that share a common Metrics parent) reaches the diamond case. At D=10 the traversal calls the method 1,024 times vs 10 with a visited guard.

Fix

Add a visited guard using the clazz itself as the key:

public static Set<Class<? extends Service>> identifyServiceInterfaces(Class<?> clazz,
        Set<Class<? extends Service>> serviceInterfaces) {
    return identifyServiceInterfaces(clazz, serviceInterfaces, new HashSet<>());
}

private static Set<Class<? extends Service>> identifyServiceInterfaces(Class<?> clazz,
        Set<Class<? extends Service>> serviceInterfaces, Set<Class<?>> visited) {
    if (clazz == null || Object.class.equals(clazz) || BootstrapService.class.equals(clazz)) {
        return serviceInterfaces;
    }
    if (!visited.add(clazz)) {                                  // guard: skip if already visited
        return serviceInterfaces;
    }
    for (Class<?> interfac3 : clazz.getInterfaces()) {
        if (Service.class.equals(interfac3) || BootstrapService.class.equals(interfac3)) {
            serviceInterfaces.add(Reflections.cast(clazz));
        }
    }
    for (Class<?> interfac3 : clazz.getInterfaces()) {
        identifyServiceInterfaces(interfac3, serviceInterfaces, visited);
    }
    identifyServiceInterfaces(clazz.getSuperclass(), serviceInterfaces, visited);
    return serviceInterfaces;
}

Alternatively, since the public API accepts a Set, the visited guard can reuse a local HashSet passed through a private overload as shown above.

Speedup

D Recursive calls (before) Recursive calls (after) Speedup
5 31 5 6×
10 1,023 10 102×
15 32,767 15 2,184×
20 1,048,575 20 52,428×

This method is called during Weld CDI container initialization to build the service registry. An application with custom CDI extensions implementing a layered Service hierarchy directly triggers the diamond case. At D=10, startup time for service discovery is 1000× worse than necessary.