package unit; import java.util.*; /** * Models Bazel FeatureSelection.run() provides-conflict check. * * SLOW: O(P×S×L) — ImmutableList.contains() O(L) per selectable in P×S nested loops. * FAST: O(P×S) — HashSet built once from enabledList; O(1) per lookup. * * CWE-407: src/main/java/com/google/devtools/build/lib/rules/cpp/FeatureSelection.java:159 */ public class BazelFeatureSelectionAlgorithmTest { // ------------------------------------------------------------------------- // Slow — ImmutableList.contains() O(L) per lookup // ------------------------------------------------------------------------- static class SlowFeatureSelection { long cmpOps = 0; boolean listContains(List list, String val) { for (String s : list) { cmpOps++; if (s.equals(val)) return true; } return false; } /** * O(P × S × L): for each provide × selectable, check enabledList membership. * Returns count of conflict checks performed. */ int run(List enabledList, Map> providesMap) { int conflicts = 0; for (Map.Entry> entry : providesMap.entrySet()) { for (String selectable : entry.getValue()) { if (listContains(enabledList, selectable)) { conflicts++; } } } return conflicts; } long ops(List enabledList, Map> providesMap) { cmpOps = 0; run(enabledList, providesMap); return cmpOps; } } // ------------------------------------------------------------------------- // Fast — HashSet built once before loop // ------------------------------------------------------------------------- static class FastFeatureSelection { long cmpOps = 0; int run(List enabledList, Map> providesMap) { Set enabledSet = new HashSet<>(enabledList); cmpOps += enabledList.size(); // build cost int conflicts = 0; for (Map.Entry> entry : providesMap.entrySet()) { for (String selectable : entry.getValue()) { cmpOps++; if (enabledSet.contains(selectable)) { conflicts++; } } } return conflicts; } long ops(List enabledList, Map> providesMap) { cmpOps = 0; run(enabledList, providesMap); return cmpOps; } } // ------------------------------------------------------------------------- // Build test data // ------------------------------------------------------------------------- static List makeEnabledList(int l) { List list = new ArrayList<>(); for (int i = 0; i < l; i++) list.add("feature_" + i); return list; } static Map> makeProvidesMap(int p, int s, int overlapStart) { Map> map = new LinkedHashMap<>(); for (int i = 0; i < p; i++) { List sels = new ArrayList<>(); for (int j = 0; j < s; j++) { // Some selectables are in enabledList (conflicts), some not sels.add("feature_" + (overlapStart + i * s + j)); } map.put("provide_" + i, sels); } return map; } public static void main(String[] args) { SlowFeatureSelection slow = new SlowFeatureSelection(); FastFeatureSelection fast = new FastFeatureSelection(); int passed = 0, total = 0; System.out.println("=== bazel-0003: FeatureSelection ImmutableList.contains O(P×S×L) ==="); // (L, P, S) configurations matching realistic Bazel C++ toolchain sizes int[][] configs = { {50, 7, 6}, // small toolchain {80, 7, 6}, // realistic (agent's estimate) {150, 10, 8}, // large toolchain {300, 15, 10} // extreme }; for (int[] cfg : configs) { int l = cfg[0], p = cfg[1], s = cfg[2]; List enabled = makeEnabledList(l); Map> provides = makeProvidesMap(p, s, 0); long sv = slow.ops(enabled, provides); long fv = fast.ops(enabled, provides); double ratio = (double) sv / Math.max(fv, 1); total++; boolean ok = sv > fv && ratio >= 5.0; System.out.printf("L=%3d P=%2d S=%2d slow=%7d fast=%5d ratio=%6.1fx %s%n", l, p, s, sv, fv, ratio, ok ? "PASS" : "FAIL"); if (ok) passed++; } // Correctness: both count same conflicts List enabled = makeEnabledList(80); Map> provides = makeProvidesMap(7, 6, 0); int sc = slow.run(enabled, provides); int fc = fast.run(enabled, provides); total++; boolean correct = sc == fc; System.out.printf("conflict count matches (%d): %s%n", sc, correct ? "PASS" : "FAIL"); if (correct) passed++; System.out.printf("%n%d/%d PASS%n", passed, total); if (passed < total) System.exit(1); } }