java-topology/defects/eclipse-jdt/patch/eclipse-jdt-diamond-recursion-CLEAN.md
russell@unturf.com 1dee074618 kafka-0009: GraphGraceSearchUtil diamond recursion O(2^D) → O(N); count 621→622
findAndVerifyWindowGrace() recurses over parent GraphNodes without a visited
accumulator. Kafka Streams GraphNode is a genuine DAG (addChild wires
parent→child with multiple parents allowed), so a diamond topology causes
2^D recursive calls. Fix: thread an IdentityHashMap<GraphNode,Long> memo
through recursion; memoize on first visit, return cached result on revisit.
8/8 unit tests PASS; D=10 defect count=3071 vs patched O(N).

Diamond-recursion CLEAN markers added for: flink, neo4j, janusgraph,
tinkerpop, dgraph, zookeeper, storm, ant, gradle, graal, eclipse-jdt,
exposed, intellij, kotlin, scala3, hibernate-0007 (prior session work
now committed).
2026-03-29 16:59:50 -04:00

47 lines
2.2 KiB
Markdown

# Eclipse JDT — Diamond Recursion CWE-407 Scan: CLEAN
**Pattern:** Recursive cycle/reachability without visited set (O(2^D) on diamond DAGs)
**Scan date:** 2026-03-29
**Scope:** `org.eclipse.jdt.core/`, `org.eclipse.jdt.core.compiler.batch/`
## Method
Searched for `hasCycle`, `isCyclic`, `isReachable`, `canReach`, `hasPath`,
`detectCycle` across all Java sources. Examined each recursive function for
a missing visited-accumulator parameter.
## Key candidates reviewed
### `ClassScope.detectHierarchyCycle()`
`org.eclipse.jdt.core.compiler.batch/.../lookup/ClassScope.java` line 1474.
Recursive — calls itself at lines 1517 and 1535. However, it avoids diamond
blowup via per-node memoization embedded in `TagBits`:
- Sets `TagBits.BeginHierarchyCheck` on each node before descending
- Checks `isHierarchyBeingActivelyConnected()` (an IN_PROGRESS flag) before recursing
- Checks `(superType.tagBits & TagBits.BeginHierarchyCheck) == 0` to skip already-visited nodes
- For binary supertypes, propagates `TagBits.HierarchyHasProblems` upward to avoid re-expansion
This is a "colored node" visited-set pattern where the visited state lives on the
node object itself rather than in an external set. Equivalent complexity to DFS
with a visited set — O(V+E). Not the diamond recursion anti-pattern.
### `InferenceContext18.isReachable()`
`org.eclipse.jdt.core.compiler.batch/.../lookup/InferenceContext18.java` line 1688.
Signature: `private boolean isReachable(Map<ConstraintFormula,Set<ConstraintFormula>> deps, ConstraintFormula from, ConstraintFormula to, Set<ConstraintFormula> nodesVisited, Set<ConstraintFormula> nodesInCycle)`
Explicitly takes a `nodesVisited` set parameter — `nodesVisited.add(from)` at line 1695
is the visited guard. CLEAN.
### `ModuleBinding.collectAllDependencies()` / `collectTransitiveDependencies()`
`org.eclipse.jdt.core.compiler.batch/.../lookup/ModuleBinding.java` lines 419, 426.
Uses `deps.add(m)` — the Set parameter itself is the visited accumulator. If `add()`
returns false (already present), the recursive call is skipped. CLEAN.
## Verdict
CLEAN for diamond recursion pattern. Eclipse JDT uses either per-node TagBits
memoization or explicit Set parameters to prevent diamond blowup. No unprotected
recursive DAG traversal found.