undefect. CWE-407 — 92 sites, 42 ecosystems

B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections.
Squash of 94 local commits onto remote master.
This commit is contained in:
russell@unturf.com 2026-03-26 19:48:18 -04:00
parent 0a580b313d
commit db29a08762
1311 changed files with 371202 additions and 1188 deletions

View file

@ -0,0 +1,344 @@
package unit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
/**
* TerraformDagTest
*
* Models three CWE-407 defects across two repos:
*
* TF-001 (HIGH) internal/dag/tarjan.go inStack()
* Defective: inStack iterates s.Stack []Vertex O(stack-depth) per call.
* Called once per edge in stronglyConnected O(V×E) total.
* Fixed: onStack map[Vertex]bool O(1) per call.
*
* TF-002 (MEDIUM) internal/dag/graph.go EdgesTo()
* Defective: EdgesTo iterates g.Edges() (all edges) filtering by target
* O(E) per call. Called inside for-range Vertices() O(V×E).
* Fixed: upEdges index gives sources for a target directly O(in-degree).
*
* SALT-001 (MEDIUM) salt/cloud/__init__.py _has_loop()
* Defective: seen is a list; `dep not in seen` is O(depth); list(seen) copy
* O(depth) per recursive call O(V²) total.
* Fixed: seen is a set; `dep not in seen` is O(1); set(seen) copy still
* O(depth) but no per-element scan.
*
* Operation counts are instrumented explicitly not wall-clock timing.
*/
public class TerraformDagTest {
// -----------------------------------------------------------------------
// TF-001: inStack modelled as ArrayList linear scan vs HashMap O(1) lookup
// -----------------------------------------------------------------------
/** Defective Tarjan inStack: iterate ArrayList<String> for membership. */
static long defectiveInStack(ArrayList<String> stack, String needle) {
long comparisons = 0;
for (String n : stack) {
comparisons++;
if (n.equals(needle)) {
return comparisons; // found return cost of this call
}
}
return comparisons; // not found
}
/**
* Simulate running stronglyConnected on a graph with V vertices and E edges.
* Each edge causes one inStack call; stack size averages V/2 (worst case V).
* Total comparisons: sum over each edge of (average stack depth).
*/
static long simulateDefectiveTarjan(int v, int edgesPerVertex) {
ArrayList<String> stack = new ArrayList<>();
for (int i = 0; i < v; i++) {
stack.add("v" + i); // push all onto stack (worst case)
}
long totalComparisons = 0;
// Each vertex has edgesPerVertex edges; each edge one inStack call.
for (int vertex = 0; vertex < v; vertex++) {
for (int e = 0; e < edgesPerVertex; e++) {
// needle not in stack in the worst path (scan to end)
totalComparisons += defectiveInStack(stack, "missing");
}
}
return totalComparisons;
}
/** Fixed Tarjan onStack: HashMap<String,Boolean> O(1) lookup. */
static long simulateFixedTarjan(int v, int edgesPerVertex) {
HashMap<String, Boolean> onStack = new HashMap<>();
for (int i = 0; i < v; i++) {
onStack.put("v" + i, true);
}
long lookups = 0;
for (int vertex = 0; vertex < v; vertex++) {
for (int e = 0; e < edgesPerVertex; e++) {
onStack.containsKey("missing"); // O(1)
lookups++;
}
}
return lookups;
}
// -----------------------------------------------------------------------
// TF-002: EdgesTo modelled as full-edge scan vs upEdges index lookup
// -----------------------------------------------------------------------
/** One Edge: source → target (both as integer IDs). */
static class Edge {
final int source, target;
Edge(int source, int target) { this.source = source; this.target = target; }
}
/**
* Defective EdgesTo: iterate all edges and filter by target.
* Returns comparison count (one per edge inspected).
*/
static long defectiveEdgesTo(ArrayList<Edge> allEdges, int targetVertex) {
long comparisons = 0;
for (Edge e : allEdges) {
comparisons++;
// filter logic result unused, we only count work
@SuppressWarnings("unused")
boolean match = (e.target == targetVertex);
}
return comparisons;
}
/**
* Fixed EdgesTo: use upEdges index HashMap<Integer, ArrayList<Integer>>
* mapping target list of sources. Cost: one map lookup + in-degree iterations.
*/
static long fixedEdgesTo(HashMap<Integer, ArrayList<Integer>> upEdges, int targetVertex) {
ArrayList<Integer> sources = upEdges.getOrDefault(targetVertex, new ArrayList<>());
// one lookup + sources.size() edge constructions
return 1 + sources.size(); // CWE-407 fix cost model: O(1 + in-degree)
}
/** Build a graph with v vertices in a chain: 0→1→2→...→(v-1). */
static ArrayList<Edge> buildAllEdges(int v) {
ArrayList<Edge> edges = new ArrayList<>();
for (int i = 0; i < v - 1; i++) {
edges.add(new Edge(i, i + 1));
}
return edges;
}
static HashMap<Integer, ArrayList<Integer>> buildUpEdges(int v) {
HashMap<Integer, ArrayList<Integer>> up = new HashMap<>();
for (int i = 0; i < v - 1; i++) {
up.computeIfAbsent(i + 1, k -> new ArrayList<>()).add(i);
}
return up;
}
// -----------------------------------------------------------------------
// SALT-001: _has_loop seen modelled as ArrayList vs HashSet membership
// -----------------------------------------------------------------------
/**
* Defective _has_loop: seen is an ArrayList.
* Counts list-scan comparisons for `val in seen` across depth recursion levels.
*/
static long defectiveHasLoopMembershipCost(int depth) {
// Simulate depth recursive calls each doing a linear scan of seen.
// At call i, seen.size() == i cost i comparisons.
// Total: 0 + 1 + 2 + ... + (depth-1) = depth*(depth-1)/2
ArrayList<String> seen = new ArrayList<>();
long comparisons = 0;
for (int i = 0; i < depth; i++) {
String val = "machine" + i;
// simulate `if val in seen` (miss val not yet added)
for (String s : seen) {
comparisons++;
if (s.equals(val)) break;
}
seen.add(val);
}
return comparisons;
}
/**
* Fixed _has_loop: seen is a HashSet.
* Each membership test is O(1); count one lookup per call.
*/
static long fixedHasLoopMembershipCost(int depth) {
HashSet<String> seen = new HashSet<>();
long lookups = 0;
for (int i = 0; i < depth; i++) {
String val = "machine" + i;
seen.contains(val); // O(1)
lookups++;
seen.add(val);
}
return lookups;
}
// -----------------------------------------------------------------------
// Test 1 TF-001: defective inStack grows O(V×E), fixed is O(E)
// -----------------------------------------------------------------------
static void test1_tf001_inStackLinearVsMap() {
int v1 = 20, v2 = 40;
int edges = 5;
long d1 = simulateDefectiveTarjan(v1, edges);
long d2 = simulateDefectiveTarjan(v2, edges);
long f1 = simulateFixedTarjan(v1, edges);
long f2 = simulateFixedTarjan(v2, edges);
// Defective: comparisons V² (V vertices × E edges × V stack depth)
// Doubling V should roughly quadruple defect ops.
double defectGrowth = (double) d2 / Math.max(1, d1);
// Fixed: lookups = V × E, linear in V.
double fixedGrowth = (double) f2 / Math.max(1, f1);
System.out.printf("test1 TF-001: v=%d→%d defect=%d→%d (%.1fx) fixed=%d→%d (%.1fx)%n",
v1, v2, d1, d2, defectGrowth, f1, f2, fixedGrowth);
assert defectGrowth > fixedGrowth
: "defect growth " + defectGrowth + " should exceed fixed growth " + fixedGrowth;
assert defectGrowth > 2.0
: "defect should grow super-linearly on 2x V, got " + defectGrowth;
assert d1 > f1
: "defect ops " + d1 + " must exceed fixed ops " + f1 + " at V=" + v1;
}
// -----------------------------------------------------------------------
// Test 2 TF-001: defect at V=100 is at least 10x more work than fix
// -----------------------------------------------------------------------
static void test2_tf001_tenXRatioAtV100() {
int v = 100, edges = 3;
long defectOps = simulateDefectiveTarjan(v, edges);
long fixedOps = simulateFixedTarjan(v, edges);
double ratio = (double) defectOps / Math.max(1, fixedOps);
System.out.printf("test2 TF-001: v=%d edges=%d defect=%d fixed=%d ratio=%.1fx%n",
v, edges, defectOps, fixedOps, ratio);
assert ratio > 10.0
: "expected defect/fixed ratio > 10x at V=100, got " + ratio;
}
// -----------------------------------------------------------------------
// Test 3 TF-002: defective EdgesTo O(E) vs fixed O(in-degree)
// -----------------------------------------------------------------------
static void test3_tf002_edgesToIndexVsScan() {
int v = 200; // chain graph: 199 edges, each vertex has in-degree 1
ArrayList<Edge> allEdges = buildAllEdges(v);
HashMap<Integer, ArrayList<Integer>> upEdges = buildUpEdges(v);
// Query EdgesTo for every vertex simulates transform_destroy_cbd loop.
long defectTotal = 0;
long fixedTotal = 0;
for (int vertex = 0; vertex < v; vertex++) {
defectTotal += defectiveEdgesTo(allEdges, vertex);
fixedTotal += fixedEdgesTo(upEdges, vertex);
}
double ratio = (double) defectTotal / Math.max(1, fixedTotal);
System.out.printf("test3 TF-002: V=%d defect_total=%d fixed_total=%d ratio=%.1fx%n",
v, defectTotal, fixedTotal, ratio);
// Defect: V calls × E edges scanned = V×(V-1) V²
// Fixed: V calls × (1 + in-degree) V + E 2V
// Ratio V/2 = 100 for V=200.
assert defectTotal > fixedTotal
: "defect total " + defectTotal + " must exceed fixed total " + fixedTotal;
assert ratio > 10.0
: "expected ratio > 10x for V=200, got " + ratio;
}
// -----------------------------------------------------------------------
// Test 4 SALT-001: seen-list O(depth²) vs seen-set O(depth)
// -----------------------------------------------------------------------
static void test4_salt001_seenListVsSet() {
int depth1 = 50;
int depth2 = 100; // double the depth
long d1 = defectiveHasLoopMembershipCost(depth1);
long d2 = defectiveHasLoopMembershipCost(depth2);
long f1 = fixedHasLoopMembershipCost(depth1);
long f2 = fixedHasLoopMembershipCost(depth2);
double defectGrowth = (double) d2 / Math.max(1, d1);
double fixedGrowth = (double) f2 / Math.max(1, f1);
// Defective: O(depth²) doubling depth quadruples comparisons
long expectedDefect50 = (long) depth1 * (depth1 - 1) / 2;
System.out.printf("test4 SALT-001: depth=%d→%d defect=%d→%d (%.1fx, expect_d50=%d) fixed=%d→%d (%.1fx)%n",
depth1, depth2, d1, d2, defectGrowth, expectedDefect50, f1, f2, fixedGrowth);
assert d1 == expectedDefect50
: "defect cost at depth=50 expected " + expectedDefect50 + " got " + d1;
assert defectGrowth > 2.0
: "defect should grow super-linearly on 2x depth, got " + defectGrowth;
assert fixedGrowth <= 2.5
: "fixed should grow at most linearly on 2x depth, got " + fixedGrowth;
assert defectGrowth > fixedGrowth
: "defect growth " + defectGrowth + " should exceed fixed growth " + fixedGrowth;
}
// -----------------------------------------------------------------------
// Test 5 SALT-001: ratio > 5x at depth=80
// -----------------------------------------------------------------------
static void test5_salt001_ratioAtDepth80() {
int depth = 80;
long defectOps = defectiveHasLoopMembershipCost(depth);
long fixedOps = fixedHasLoopMembershipCost(depth);
double ratio = (double) defectOps / Math.max(1, fixedOps);
// Defect: depth*(depth-1)/2 = 80*79/2 = 3160
// Fixed: depth = 80
// Ratio: ~39.5x
long expectedDefect = (long) depth * (depth - 1) / 2;
System.out.printf("test5 SALT-001: depth=%d defect=%d (expect=%d) fixed=%d ratio=%.1fx%n",
depth, defectOps, expectedDefect, fixedOps, ratio);
assert defectOps == expectedDefect
: "defect comparisons=" + defectOps + " expected=" + expectedDefect;
assert ratio > 5.0
: "expected ratio > 5x at depth=80, got " + ratio;
}
// -----------------------------------------------------------------------
// Main
// -----------------------------------------------------------------------
public static void main(String[] args) {
System.out.println("=== TerraformDagTest ===");
System.out.println("Modelling CWE-407: TF-001 (inStack), TF-002 (EdgesTo), SALT-001 (_has_loop)");
System.out.println();
test1_tf001_inStackLinearVsMap();
System.out.println(" PASS test1_tf001_inStackLinearVsMap");
test2_tf001_tenXRatioAtV100();
System.out.println(" PASS test2_tf001_tenXRatioAtV100");
test3_tf002_edgesToIndexVsScan();
System.out.println(" PASS test3_tf002_edgesToIndexVsScan");
test4_salt001_seenListVsSet();
System.out.println(" PASS test4_salt001_seenListVsSet");
test5_salt001_ratioAtDepth80();
System.out.println(" PASS test5_salt001_ratioAtDepth80");
System.out.println();
System.out.println("All 5 tests PASSED.");
}
}