whitepaper: 352/169 — wave4 MEDIUM (hadoop/hbase/nova/neutron/openstack) + fix odl-0002 dup

This commit is contained in:
russell@unturf.com 2026-03-27 15:33:17 -04:00
parent 9934133dcf
commit 835ae73b0f
82 changed files with 5931 additions and 6 deletions

View file

@ -0,0 +1,216 @@
package unit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
/**
* PuppetGraphTest
*
* Models one CWE-407 defect in puppetlabs/puppet:
*
* PUP-001 (LOW, error path) lib/puppet/graph/simple_graph.rb:214
* paths_in_cycle() BFS: frame[1].member?(frame[0]) where frame[1] is a
* growing Array. Each membership test is O(path_length); paths grow as
* BFS expands; in a fully connected cycle of length N this produces
* O(N^3) total comparisons.
*
* Fix: carry a parallel Set alongside the Array in each BFS frame.
* frame[2].include?(frame[0]) is O(1) average. Array is retained for
* ordered path output.
*
* All measurements are instrumented operation counts, not wall-clock timing.
*/
public class PuppetGraphTest {
// -----------------------------------------------------------------------
// PUP-001 modelling helpers
// Models BFS over a simple directed cycle: 0 -> 1 -> 2 -> ... -> (N-1) -> 0
// BFS explores from vertex 0; paths grow until cycle is detected.
//
// Defective: frame path is ArrayList; membership test iterates the whole list.
// Fixed: parallel HashSet; membership test is O(1).
// -----------------------------------------------------------------------
/**
* Simulates defective paths_in_cycle BFS on a simple cycle of length N.
* Returns total membership-test comparisons performed.
*
* BFS frame = [vertex, path_as_ArrayList]
* Cycle detection: path.contains(vertex) -- O(path.size()) per call
*/
static long pup001Defective(int cycleLen) {
// Use pair representation: ArrayList<int[]> where int[0]=vertex, index into paths list
// But model directly with operation counting
// BFS: frame = (vertex, path ArrayList)
ArrayList<Object[]> stack = new ArrayList<>();
ArrayList<Integer> emptyPath = new ArrayList<>();
stack.add(new Object[]{0, emptyPath});
long comparisons = 0;
int steps = 0;
int maxSteps = cycleLen * cycleLen * 4; // safety bound
while (!stack.isEmpty() && steps < maxSteps) {
steps++;
Object[] frame = stack.remove(0); // shift (BFS)
int vertex = (Integer) frame[0];
@SuppressWarnings("unchecked")
ArrayList<Integer> path = (ArrayList<Integer>) frame[1];
// Defective: path.contains(vertex) -- O(path.size()) comparisons
boolean inPath = false;
for (Integer p : path) {
comparisons++;
if (p == vertex) {
inPath = true;
break;
}
}
if (inPath) {
// cycle found stop this branch
} else {
// extend path and push next vertex
ArrayList<Integer> newPath = new ArrayList<>(path);
newPath.add(vertex);
int next = (vertex + 1) % cycleLen;
stack.add(new Object[]{next, newPath});
}
}
return comparisons;
}
/**
* Simulates fixed paths_in_cycle BFS on a simple cycle of length N.
* Returns total membership-test operations (each O(1) hash lookup = 1 op).
*
* BFS frame = [vertex, path_ArrayList, path_HashSet]
* Cycle detection: pathSet.contains(vertex) -- O(1) per call
*/
static long pup001Fixed(int cycleLen) {
ArrayList<Object[]> stack = new ArrayList<>();
ArrayList<Integer> emptyPath = new ArrayList<>();
HashSet<Integer> emptySet = new HashSet<>();
stack.add(new Object[]{0, emptyPath, emptySet});
long lookups = 0;
int steps = 0;
int maxSteps = cycleLen * cycleLen * 4;
while (!stack.isEmpty() && steps < maxSteps) {
steps++;
Object[] frame = stack.remove(0);
int vertex = (Integer) frame[0];
@SuppressWarnings("unchecked")
ArrayList<Integer> path = (ArrayList<Integer>) frame[1];
@SuppressWarnings("unchecked")
HashSet<Integer> pathSet = (HashSet<Integer>) frame[2];
// Fixed: pathSet.contains(vertex) -- O(1) lookup
lookups++;
boolean inPath = pathSet.contains(vertex);
if (inPath) {
// cycle found stop this branch
} else {
ArrayList<Integer> newPath = new ArrayList<>(path);
newPath.add(vertex);
@SuppressWarnings("unchecked")
HashSet<Integer> newSet = (HashSet<Integer>) pathSet.clone();
newSet.add(vertex);
int next = (vertex + 1) % cycleLen;
stack.add(new Object[]{next, newPath, newSet});
}
}
return lookups;
}
// -----------------------------------------------------------------------
// Test 1 PUP-001: defect costs more than fix at cycle_len=20
// -----------------------------------------------------------------------
static void test1_pup001_pathMembershipSet() {
int N = 20;
long defectCost = pup001Defective(N);
long fixedCost = pup001Fixed(N);
double ratio = (double) defectCost / Math.max(1, fixedCost);
System.out.printf("test1 PUP-001: cycle_len=%d defect=%d fixed=%d ratio=%.1fx%n",
N, defectCost, fixedCost, ratio);
assert defectCost > fixedCost
: "defect must be more expensive than fix at cycle_len=" + N
+ " (defect=" + defectCost + ", fixed=" + fixedCost + ")";
assert ratio >= 8.0
: "expected ratio >= 8x at cycle_len=" + N + ", got " + ratio;
}
// -----------------------------------------------------------------------
// Test 2 PUP-001: scaling doubling cycle length grows defect faster
// than the fix (super-linear vs near-linear)
// -----------------------------------------------------------------------
static void test2_pup001_scalingGrowth() {
int N1 = 15;
int N2 = 30; // doubled
long d1 = pup001Defective(N1);
long d2 = pup001Defective(N2);
long f1 = pup001Fixed(N1);
long f2 = pup001Fixed(N2);
double defectGrowth = (double) d2 / Math.max(1, d1);
double fixedGrowth = (double) f2 / Math.max(1, f1);
System.out.printf("test2 PUP-001: N=%d→%d defect=%d→%d (%.2fx) fixed=%d→%d (%.2fx)%n",
N1, N2, d1, d2, defectGrowth, f1, f2, fixedGrowth);
assert defectGrowth > 2.0
: "defect should grow super-linearly on 2x cycle_len, got " + defectGrowth;
assert fixedGrowth <= 3.0
: "fixed should grow at most linearly (×2 ± slack) on 2x cycle_len, got " + fixedGrowth;
assert defectGrowth > fixedGrowth
: "defect growth " + defectGrowth + " should exceed fixed growth " + fixedGrowth;
}
// -----------------------------------------------------------------------
// Test 3 PUP-001: ratio at cycle_len=25 exceeds 5x
// -----------------------------------------------------------------------
static void test3_pup001_ratioAt25() {
int N = 25;
long defectOps = pup001Defective(N);
long fixedOps = pup001Fixed(N);
double ratio = (double) defectOps / Math.max(1, fixedOps);
System.out.printf("test3 PUP-001: cycle_len=%d defect=%d fixed=%d ratio=%.1fx%n",
N, defectOps, fixedOps, ratio);
assert ratio > 5.0
: "expected ratio > 5x at cycle_len=25, got " + ratio;
}
// -----------------------------------------------------------------------
// Main
// -----------------------------------------------------------------------
public static void main(String[] args) {
System.out.println("=== PuppetGraphTest ===");
System.out.println("Modelling CWE-407: PUP-001 (paths_in_cycle BFS Array#member? O(N^3))");
System.out.println();
test1_pup001_pathMembershipSet();
System.out.println(" PASS test1_pup001_pathMembershipSet");
test2_pup001_scalingGrowth();
System.out.println(" PASS test2_pup001_scalingGrowth");
test3_pup001_ratioAt25();
System.out.println(" PASS test3_pup001_ratioAt25");
System.out.println();
System.out.println("3/3 PASS");
}
}