package unit; import java.util.*; /** * CWE-407 unit test: podman determineCapAddDropFromCapabilities * File: libpod/kube.go:1280 — determineCapAddDropFromCapabilities * * Slow: for each cap, calls slices.Contains on opposing slice → O(n²) * Fast: build maps for both slices first → O(n) * * Run: javac -d . CapDiffAlgorithm.java && java -ea unit.CapDiffAlgorithm */ public class CapDiffAlgorithm { // ── Slow implementation ─────────────────────────────────────────────────── static class SlowCapDiff { final long ops; final List drop; final List add; SlowCapDiff(List defaultCaps, List containerCaps) { long count = 0; Map dedupDrop = new HashMap<>(); Map dedupAdd = new HashMap<>(); List dropList = new ArrayList<>(); List addList = new ArrayList<>(); // Find dropped: in defaultCaps but not containerCaps for (String cap : defaultCaps) { boolean found = false; for (String c : containerCaps) { // slices.Contains — O(n) scan count++; if (c.equals(cap)) { found = true; break; } } if (!found && !dedupDrop.containsKey(cap)) { dropList.add(cap); dedupDrop.put(cap, true); } } // Find added: in containerCaps but not defaultCaps for (String cap : containerCaps) { boolean found = false; for (String c : defaultCaps) { // slices.Contains — O(n) scan count++; if (c.equals(cap)) { found = true; break; } } if (!found && !dedupAdd.containsKey(cap)) { addList.add(cap); dedupAdd.put(cap, true); } } this.ops = count; this.drop = dropList; this.add = addList; } } // ── Fast implementation ─────────────────────────────────────────────────── static class FastCapDiff { final long ops; final List drop; final List add; FastCapDiff(List defaultCaps, List containerCaps) { long count = 0; // Build sets — O(n) each Set defaultSet = new HashSet<>(defaultCaps.size() * 2); Set containerSet = new HashSet<>(containerCaps.size() * 2); for (String c : defaultCaps) { count++; defaultSet.add(c); } for (String c : containerCaps) { count++; containerSet.add(c); } List dropList = new ArrayList<>(); List addList = new ArrayList<>(); Set dedupDrop = new HashSet<>(); Set dedupAdd = new HashSet<>(); for (String cap : defaultCaps) { count++; // O(1) set lookup if (!containerSet.contains(cap) && dedupDrop.add(cap)) { dropList.add(cap); } } for (String cap : containerCaps) { count++; // O(1) set lookup if (!defaultSet.contains(cap) && dedupAdd.add(cap)) { addList.add(cap); } } this.ops = count; this.drop = dropList; this.add = addList; } } // ── Node / Result ───────────────────────────────────────────────────────── static class Node { final String cap; Node(String cap) { this.cap = cap; } } static class Result { final long slowOps, fastOps; final List slowDrop, fastDrop; final List slowAdd, fastAdd; Result(long slowOps, long fastOps, List slowDrop, List fastDrop, List slowAdd, List fastAdd) { this.slowOps = slowOps; this.fastOps = fastOps; this.slowDrop = slowDrop; this.fastDrop = fastDrop; this.slowAdd = slowAdd; this.fastAdd = fastAdd; } } // ── test helpers ────────────────────────────────────────────────────────── static int passed = 0, total = 0; static void test(String name, boolean condition) { total++; if (condition) { passed++; System.out.println("PASS: " + name); } else { System.out.println("FAIL: " + name); } } static List caps(int n) { List c = new ArrayList<>(n); for (int i = 0; i < n; i++) c.add("CAP_" + i); return c; } static Result run(List defaults, List container) { SlowCapDiff slow = new SlowCapDiff(defaults, container); FastCapDiff fast = new FastCapDiff(defaults, container); return new Result(slow.ops, fast.ops, slow.drop, fast.drop, slow.add, fast.add); } public static void main(String[] args) { // T1: Realistic — N=41 default, N=41 container (some overlap) { List defaults = caps(41); List container = caps(41); // Container has 5 extra caps and dropped 5 defaults for (int i = 41; i < 46; i++) container.add("CAP_EXTRA_" + i); container.subList(0, 5).clear(); // remove first 5 defaults Result r = run(defaults, container); test("T1-slow-quadratic [N=41]", r.slowOps >= 41L * 36 / 2); // at least partial n*m work test("T1-fast-linear [N=41]", r.fastOps <= 2 * 41 + 2 * 46 + 10); double speedup = (double) r.slowOps / r.fastOps; test("T1-speedup>=5x", speedup >= 5.0); System.out.printf(" slow=%d ops, fast=%d ops, speedup=%.1fx%n", r.slowOps, r.fastOps, speedup); List sd = new ArrayList<>(r.slowDrop); Collections.sort(sd); List fd = new ArrayList<>(r.fastDrop); Collections.sort(fd); test("T1-drop-results-match", sd.equals(fd)); List sa = new ArrayList<>(r.slowAdd); Collections.sort(sa); List fa = new ArrayList<>(r.fastAdd); Collections.sort(fa); test("T1-add-results-match", sa.equals(fa)); } // T2: Large cap sets — N=200 { List defaults = caps(200); List container = caps(200); for (int i = 200; i < 220; i++) container.add("CAP_EXTRA_" + i); container.subList(0, 20).clear(); Result r = run(defaults, container); double speedup = (double) r.slowOps / r.fastOps; test("T2-slow-quadratic [N=200]", r.slowOps >= 200L * 180 / 2); test("T2-fast-linear [N=200]", r.fastOps <= 2 * 200 + 2 * 220 + 10); test("T2-speedup>=20x", speedup >= 20.0); System.out.printf(" slow=%d ops, fast=%d ops, speedup=%.1fx%n", r.slowOps, r.fastOps, speedup); List sd = new ArrayList<>(r.slowDrop); Collections.sort(sd); List fd = new ArrayList<>(r.fastDrop); Collections.sort(fd); test("T2-drop-match", sd.equals(fd)); List sa = new ArrayList<>(r.slowAdd); Collections.sort(sa); List fa = new ArrayList<>(r.fastAdd); Collections.sort(fa); test("T2-add-match", sa.equals(fa)); } // T3: Identical cap sets — nothing dropped or added { List c = caps(41); Result r = run(c, new ArrayList<>(c)); test("T3-identical-drop-empty", r.fastDrop.isEmpty()); test("T3-identical-add-empty", r.fastAdd.isEmpty()); test("T3-results-match-slow", r.slowDrop.equals(r.fastDrop) && r.slowAdd.equals(r.fastAdd)); } // T4: Completely disjoint sets { List defaults = caps(20); List container = new ArrayList<>(); for (int i = 20; i < 40; i++) container.add("CAP_" + i); Result r = run(defaults, container); // All defaults are dropped, all container caps are added test("T4-all-dropped", r.fastDrop.size() == 20); test("T4-all-added", r.fastAdd.size() == 20); List sd = new ArrayList<>(r.slowDrop); Collections.sort(sd); List fd = new ArrayList<>(r.fastDrop); Collections.sort(fd); test("T4-results-match", sd.equals(fd)); } System.out.println(); System.out.printf("%d/%d PASS%n", passed, total); if (passed != total) System.exit(1); } }