package unit; import java.util.*; /** * actix-0001: CWE-407 actix-web introspection update_unique O(R×G) Vec linear dedup. * * Simulates the defective update_unique() pattern from actix-web's * introspection.rs:984-989: * * fn update_unique(existing: &mut Vec, new_items: &[T]) { * for item in new_items { * if !existing.contains(item) { // O(E) linear scan * existing.push(item.clone()); * } * } * } * * Called once per route registration for guards, patterns, and methods vecs. * With R routes sharing a scope and G unique guards accumulating, total work * is O(R × G). * * Fix: pre-build a HashSet for O(1) membership, reducing to O(R + G). */ public class ActixUpdateUniqueAlgorithm { static long slowOps = 0; static long fastOps = 0; // --- SLOW: Vec.contains() linear scan (actix-web defective pattern) --- static void updateUniqueSlow(List existing, List newItems) { for (String item : newItems) { slowOps++; boolean found = false; for (String e : existing) { // O(E) inner scan slowOps++; if (e.equals(item)) { found = true; break; } } if (!found) { existing.add(item); } } } // --- FAST: HashSet membership check O(1) per item --- static void updateUniqueFast(List existing, Set existingSet, List newItems) { for (String item : newItems) { fastOps++; if (!existingSet.contains(item)) { existing.add(item); existingSet.add(item); } } } // Simulate R route registrations, each contributing G guard names to a shared path's accumulator. // In actix-web: register_pattern_detail() calls update_unique() for guards on each route. static List simulateSlow(int R, int G) { List accumulated = new ArrayList<>(); for (int r = 0; r < R; r++) { List routeGuards = new ArrayList<>(); for (int g = 0; g < G; g++) { // Routes share some guards + add one unique guard each routeGuards.add("guard_" + (g % (G / 2 + 1))); } routeGuards.add("route_guard_" + r); updateUniqueSlow(accumulated, routeGuards); } return accumulated; } static List simulateFast(int R, int G) { List accumulated = new ArrayList<>(); Set accumulatedSet = new HashSet<>(); for (int r = 0; r < R; r++) { List routeGuards = new ArrayList<>(); for (int g = 0; g < G; g++) { routeGuards.add("guard_" + (g % (G / 2 + 1))); } routeGuards.add("route_guard_" + r); updateUniqueFast(accumulated, accumulatedSet, routeGuards); } return accumulated; } public static void main(String[] args) { System.out.println("actix-0001: update_unique O(R×G) Vec linear dedup vs HashSet"); System.out.println("============================================================="); int[] sizes = {50, 100, 200, 500}; int passes = 0; int failures = 0; for (int N : sizes) { slowOps = 0; fastOps = 0; int R = N; // routes sharing a scope int G = 20; // guards per route registration List slowResult = simulateSlow(R, G); List fastResult = simulateFast(R, G); // Sort both for comparison List sortedSlow = new ArrayList<>(slowResult); List sortedFast = new ArrayList<>(fastResult); Collections.sort(sortedSlow); Collections.sort(sortedFast); boolean match = sortedSlow.equals(sortedFast); double ratio = slowOps > 0 ? (double) slowOps / Math.max(fastOps, 1) : 0; String status = (match && ratio >= 5.0) ? "PASS" : "FAIL"; System.out.printf(" N=%3d routes, G=%2d guards/reg: slow=%7d ops fast=%6d ops ratio=%.1fx result_match=%s [%s]%n", R, G, slowOps, fastOps, ratio, match, status); if (match && ratio >= 5.0) { passes++; } else { failures++; if (!match) { System.out.println(" ERROR: slow and fast results differ!"); System.out.println(" slow size=" + sortedSlow.size() + " fast size=" + sortedFast.size()); } if (ratio < 5.0) { System.out.printf(" ERROR: ratio %.1fx below required 5x minimum%n", ratio); } } } System.out.println(); // Larger test: G=50 guards per route (high guard density scenario) System.out.println("High-density guard test (R=500, G=50 guards/reg):"); { int R = 500; int G = 50; slowOps = 0; fastOps = 0; List slowResult = simulateSlow(R, G); List fastResult = simulateFast(R, G); List sortedSlow = new ArrayList<>(slowResult); List sortedFast = new ArrayList<>(fastResult); Collections.sort(sortedSlow); Collections.sort(sortedFast); boolean match = sortedSlow.equals(sortedFast); double ratio = (double) slowOps / Math.max(fastOps, 1); String status = (match && ratio >= 5.0) ? "PASS" : "FAIL"; System.out.printf(" R=%d routes, G=%d: slow=%d ops fast=%d ops ratio=%.1fx match=%s [%s]%n", R, G, slowOps, fastOps, ratio, match, status); if (match && ratio >= 5.0) passes++; else failures++; } System.out.println(); System.out.printf("%d/%d PASS%n", passes, passes + failures); if (failures > 0) { System.exit(1); } } }