diamond hunt: godot-0009/0010 + meson-0002 + typeorm-0004/0005 + ts-0003; count 629→635
New diamond recursion defects (O(2^D) → O(N)): - godot-0009: Font::_is_cyclic no visited set — CJK fallback diamond, 2648x at F=4,D=8 - godot-0010: Font::_update_rids_fb no visited set — duplicate RIDs + O(N^2) hot path - meson-0002: get_internal_static_libraries_recurse link_whole guard missing — 132x at D=10 - typescript-0003: hasBaseType inner check() no visited set — 1024x at D=10; hot on instanceof New O(N²) defects: - typeorm-0004: SubjectTopologicalSorter Array.indexOf dedup — 200x at N=400 - typeorm-0005: DepGraph.createDFS result.indexOf + addDependency edge dedup — 300x at N=600 CLEAN confirmed (diamond recursion sweep): bazel, cargo, cmake, composer, dgl, diesel, doctrine-orm, efcore, helm, mybatis, networkx-deeper, ninja, npm-arborist, peewee, pip, rubygems, seaorm, sqlalchemy, swift UNDF: 571→578 assigned; MOAD count: 629→635
This commit is contained in:
parent
ebfcdd3db5
commit
3986d8dc50
46 changed files with 2339 additions and 1 deletions
BIN
defects/typescript/unit/TypeScriptHasBaseTypeTest.class
Normal file
BIN
defects/typescript/unit/TypeScriptHasBaseTypeTest.class
Normal file
Binary file not shown.
155
defects/typescript/unit/TypeScriptHasBaseTypeTest.java
Normal file
155
defects/typescript/unit/TypeScriptHasBaseTypeTest.java
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
import java.util.*;
|
||||
|
||||
public class TypeScriptHasBaseTypeTest {
|
||||
|
||||
static int defectiveCallCount;
|
||||
|
||||
static boolean defectiveCheck(Map<String, List<String>> baseTypes, String current, String target) {
|
||||
defectiveCallCount++;
|
||||
if (current.equals(target)) return true;
|
||||
List<String> bases = baseTypes.getOrDefault(current, Collections.emptyList());
|
||||
for (String base : bases) {
|
||||
if (defectiveCheck(baseTypes, base, target)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int fixedCallCount;
|
||||
|
||||
static boolean fixedCheck(Map<String, List<String>> baseTypes, String current, String target, Set<String> seen) {
|
||||
fixedCallCount++;
|
||||
if (current.equals(target)) return true;
|
||||
if (seen.contains(current)) return false;
|
||||
seen.add(current);
|
||||
List<String> bases = baseTypes.getOrDefault(current, Collections.emptyList());
|
||||
for (String base : bases) {
|
||||
if (fixedCheck(baseTypes, base, target, seen)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean hasBaseTypeFixed(Map<String, List<String>> baseTypes, String type, String checkBase) {
|
||||
Set<String> seen = new HashSet<>();
|
||||
return fixedCheck(baseTypes, type, checkBase, seen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a diamond DAG of depth D with unique internal nodes:
|
||||
*
|
||||
* D=1: A0 extends B0, B1; B0 extends BOTTOM; B1 extends BOTTOM
|
||||
* check("A0", "MISSING") visits: A0, B0, BOTTOM(x1), B1, BOTTOM(x2)
|
||||
* but BOTTOM has no bases so it terminates quickly.
|
||||
*
|
||||
* True 2^D blowup: binary-branching DAG where every internal node fans
|
||||
* out to 2 children that reconverge at a shared grandchild.
|
||||
*
|
||||
* Depth D:
|
||||
* root → L, R
|
||||
* L → LL, LR
|
||||
* R → RL, RR
|
||||
* LL, LR, RL, RR all → SHARED_GRANDCHILD
|
||||
* etc. Each "diamond" layer doubles the paths to the shared bottom.
|
||||
*
|
||||
* Simpler construction: chained diamond.
|
||||
* d0: n0 → [n0L, n0R], n0L → n1, n0R → n1
|
||||
* d1: n1 → [n1L, n1R], n1L → n2, n1R → n2
|
||||
* ...
|
||||
* bottom: n(D) (leaf)
|
||||
*
|
||||
* Checking n0 for "MISSING" (not in graph):
|
||||
* Without visited: visits n0, n0L, n1, n1L, n2, ..., nD (left chain)
|
||||
* then backtracks to n0R, n1, n1L, n2, ..., nD (AGAIN!)
|
||||
* → 2^D visits to nD
|
||||
* With visited: each node visited once → O(D) total
|
||||
*/
|
||||
static Map<String, List<String>> buildChainedDiamond(int depth) {
|
||||
Map<String, List<String>> graph = new HashMap<>();
|
||||
// n0 → [n0L, n0R]; n0L → n1; n0R → n1
|
||||
// n1 → [n1L, n1R]; n1L → n2; n1R → n2
|
||||
// ...
|
||||
// n(depth-1) → [n(d-1)L, n(d-1)R]; both → n(depth)
|
||||
// n(depth) is a leaf
|
||||
for (int d = 0; d < depth; d++) {
|
||||
String node = "n" + d;
|
||||
String left = "n" + d + "L";
|
||||
String right = "n" + d + "R";
|
||||
String next = "n" + (d + 1);
|
||||
graph.put(node, Arrays.asList(left, right));
|
||||
graph.put(left, Arrays.asList(next));
|
||||
graph.put(right, Arrays.asList(next));
|
||||
}
|
||||
// n(depth) is a leaf - no bases
|
||||
return graph;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== TypeScript hasBaseType Diamond Recursion CWE-407 ===");
|
||||
System.out.println("Query: hasBaseType(root, 'MISSING') — forces full traversal");
|
||||
System.out.println();
|
||||
System.out.printf("%-6s %-12s %-10s %-8s%n", "Depth", "Defective", "Fixed", "Ratio");
|
||||
System.out.println("--------------------------------------");
|
||||
|
||||
boolean allPass = true;
|
||||
|
||||
for (int depth : new int[]{1, 2, 3, 5, 7, 10, 15}) {
|
||||
Map<String, List<String>> graph = buildChainedDiamond(depth);
|
||||
|
||||
defectiveCallCount = 0;
|
||||
boolean defectiveResult = defectiveCheck(graph, "n0", "MISSING");
|
||||
|
||||
fixedCallCount = 0;
|
||||
boolean fixedResult = hasBaseTypeFixed(graph, "n0", "MISSING");
|
||||
|
||||
double ratio = (double) defectiveCallCount / fixedCallCount;
|
||||
|
||||
System.out.printf("D=%-4d %-12d %-10d %-8.1fx%n",
|
||||
depth, defectiveCallCount, fixedCallCount, ratio);
|
||||
|
||||
if (defectiveResult != fixedResult) {
|
||||
System.err.println("FAIL: result mismatch at depth " + depth
|
||||
+ " (defective=" + defectiveResult + " fixed=" + fixedResult + ")");
|
||||
allPass = false;
|
||||
}
|
||||
if (depth >= 7 && ratio < 10.0) {
|
||||
System.err.println("FAIL: expected >10x ratio at depth " + depth + ", got " + ratio);
|
||||
allPass = false;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
|
||||
// Also test: hasBaseType returns true correctly for a real ancestor
|
||||
{
|
||||
Map<String, List<String>> graph = buildChainedDiamond(3);
|
||||
// n3 IS reachable from n0 via n0→n0L→n1→n1L→n2→n2L→n3
|
||||
boolean r1 = defectiveCheck(graph, "n0", "n3");
|
||||
boolean r2 = hasBaseTypeFixed(graph, "n0", "n3");
|
||||
if (!r1 || !r2) {
|
||||
System.err.println("FAIL: should return true when target IS reachable");
|
||||
allPass = false;
|
||||
} else {
|
||||
System.out.println("Correctness check (found=true): PASS");
|
||||
}
|
||||
}
|
||||
|
||||
// Test: hasBaseType returns false for non-ancestor
|
||||
{
|
||||
Map<String, List<String>> graph = buildChainedDiamond(3);
|
||||
boolean r1 = defectiveCheck(graph, "n0", "MISSING");
|
||||
boolean r2 = hasBaseTypeFixed(graph, "n0", "MISSING");
|
||||
if (r1 || r2) {
|
||||
System.err.println("FAIL: should return false for non-ancestor");
|
||||
allPass = false;
|
||||
} else {
|
||||
System.out.println("Correctness check (not-found=false): PASS");
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
if (allPass) {
|
||||
System.out.println("PASS — exponential blowup confirmed, fix reduces to O(N)");
|
||||
} else {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
defects/typescript/unit/unit/TypeScriptHasBaseTypeTest.class
Normal file
BIN
defects/typescript/unit/unit/TypeScriptHasBaseTypeTest.class
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue