diamond-scan: fix collisions, add remaining diamond defects from parallel agents

Renumbering fixes (collisions with pre-existing IDs):
- spring-0001-annotations-scanner → spring-0007 (spring-0001 was already assigned)
- hibernate-0001-class-hierarchy-helper → hibernate-validator-0003 (wrong ecosystem/numbering)
- django-0006-migrations-flatten-bases → django-0007 (django-0006 was already assigned)

New diamond defects from agents that rate-limited before committing:
- micronaut-0007: SuperclassAwareTypeVisitor.getInterfaces O(2^D) (new site)
- quarkus-0005: ConfigMappingUtils.collectInterfacesRec O(2^D) (new site)
- weld-0005: Services.identifyServiceInterfaces O(2^D) (new site)
- typescript-0005: hasBaseType O(2^D) diamond interface hierarchy
- rails-0019: Digestor#dependency_digest Array#include? O(N²) cycle detection

CLEAN: go, rustc (diamond recursion patterns absent)
This commit is contained in:
russell@unturf.com 2026-03-29 20:23:42 -04:00
parent bb1a6f002f
commit 39981c70ad
10 changed files with 617 additions and 4 deletions

View file

@ -0,0 +1,94 @@
# 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
```java
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:
```java
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.