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).
1.3 KiB
Apache Ant — 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: src/main/org/apache/tools/ant/
Method
Searched for isCyclic, hasCycle, createsCycle, addsCycle, willCycle,
isReachable, canReach, hasPath, detectCycle across all Java sources.
Checked each hit for recursive traversal lacking a visited-accumulator parameter.
Key candidate: Project.tsort()
src/main/org/apache/tools/ant/Project.java lines 1898–1939: the target dependency
topological sort passes a Hashtable<String, String> state through every recursive
call. State values are VISITING/VISITED. This is a proper DFS with O(1) visit
check per node — not the diamond recursion anti-pattern.
Other candidates
| File | Method | Verdict |
|---|---|---|
Project.java |
tsort() |
Passes state Hashtable — CLEAN |
taskdefs/optional/depend/Depend.java |
isRmiStub() / isStub() |
Not recursive on a DAG — CLEAN |
taskdefs/condition/IsReachable.java |
Network connectivity check | Not a graph traversal — CLEAN |
Verdict
CLEAN. No diamond recursion CWE-407 found. Ant's dependency resolution uses a state-tracking Hashtable (equivalent to a visited set) through all recursive calls.