# UNDF: UNDF-2026-000000416
# UNDF: (pending)
# hazelcast-0002: ClassLoaderUtil.addOwnInterfaces — O(2^D) diamond re-traversal; Collections.addAll() return value ignored

## CWE-407 — Algorithmic Complexity: O(2^D) recursive diamond re-traversal in class interface hierarchy collection

| Field        | Value |
|--------------|-------|
| ID           | hazelcast-0002 |
| Severity     | HIGH |
| Ecosystem    | hazelcast |
| Package      | hazelcast |
| File         | `hazelcast/src/main/java/com/hazelcast/internal/nio/ClassLoaderUtil.java` |
| Lines        | 387–393 |
| Complexity   | O(2^D) on diamond interface hierarchies |
| Hot path     | Called from `getAllInterfaces()` → `implementsInterfaceWithSameName()` during class loading |

## Defect

`ClassLoaderUtil.addOwnInterfaces` collects interfaces into a `Collection<Class<?>> allInterfaces`
(backed by a `HashSet` at the call site in `getAllInterfaces`). Although items are added to a Set,
the recursion guard is MISSING — `Collections.addAll` fills the set but the `for` loop recurses
unconditionally, ignoring whether each interface was already present:

```java
// ClassLoaderUtil.java:387-393 (DEFECT)
private static void addOwnInterfaces(Class<?> clazz, Collection<Class<?>> allInterfaces) {
    Class<?>[] interfaces = clazz.getInterfaces();
    Collections.addAll(allInterfaces, interfaces);   // adds items — return values IGNORED
    for (Class cl : interfaces) {
        addOwnInterfaces(cl, allInterfaces);         // DEFECT: recurses unconditionally
    }
}
```

On a diamond (I1 and I2 both extend Base; clazz implements I1 and I2):
1. `Collections.addAll(allInterfaces, [I1, I2])` → both added
2. Loop: `addOwnInterfaces(I1)` → adds Base; recurses into Base
3. Loop: `addOwnInterfaces(I2)` → `Collections.addAll(allInterfaces, [Base])` — add returns false
   (Base already present) — IGNORED; loop still recurses into Base again

At diamond depth D, Base is visited 2^D times.

This is a second distinct occurrence of the same pattern found in `SerializationUtil.getInterfaces`
(hazelcast-0001) — both share the `Collections.addAll + unconditional loop` anti-pattern.

## Fix

Replace `Collections.addAll + unconditional loop` with a per-element `allInterfaces.add()` guard:

```java
// AFTER — O(N+E) where N=interfaces, E=inheritance edges
private static void addOwnInterfaces(Class<?> clazz, Collection<Class<?>> allInterfaces) {
    for (Class<?> cl : clazz.getInterfaces()) {
        if (allInterfaces.add(cl)) {          // add returns false if already present → skip
            addOwnInterfaces(cl, allInterfaces); // only recurse if newly added
        }
    }
}
```

## Speedup

| Diamond depth (D) | Before (visits) | After (visits) | Speedup |
|------------------|----------------|----------------|---------|
| 5                | 31             | 5              | 6×      |
| 10               | 1,023          | 10             | 102×    |
| 15               | 32,767         | 15             | 2,184×  |
| 20               | 1,048,575      | 20             | 52,428× |

Growth before: O(2^D). Growth after: O(D).
