package unit; import java.util.*; /** * CWE-407 unit test: cmake-0002 * GetDirectoriesWithBacktraces — O(n*m) std::find inside loop vs O(n+m) map lookup. * * Simulates CMake's GetDirectoriesWithBacktraces(): * slow: for each orderedDir, scan targetLinkDirs linearly → O(n*m) * fast: build HashMap from targetLinkDirs, then lookup → O(n+m) */ public class GetDirectoriesAlgorithm { // Slow: O(n*m) — mirrors std::find inside for loop static long slowGetDirectories(List orderedDirs, List targetLinkDirs) { long ops = 0; List result = new ArrayList<>(); for (String dir : orderedDirs) { boolean found = false; for (String t : targetLinkDirs) { // O(m) scan per element ops++; if (t.equals(dir)) { result.add(t + "#BT"); found = true; break; } } if (!found) result.add(dir); } return ops; } // Fast: O(n+m) — build map then lookup static long fastGetDirectories(List orderedDirs, List targetLinkDirs) { long ops = 0; Map dirIndex = new HashMap<>(targetLinkDirs.size() * 2); for (String t : targetLinkDirs) { ops++; dirIndex.put(t, t + "#BT"); } List result = new ArrayList<>(); for (String dir : orderedDirs) { ops++; String bt = dirIndex.get(dir); result.add(bt != null ? bt : dir); } return ops; } public static void main(String[] args) { int[] sizes = {100, 500, 1000}; int passed = 0, total = 0; for (int N : sizes) { // Build N ordered dirs, half of which are in targetLinkDirs List orderedDirs = new ArrayList<>(N); List targetLinkDirs = new ArrayList<>(N); for (int i = 0; i < N; i++) { orderedDirs.add("/usr/lib/dir" + i); } for (int i = 0; i < N; i += 2) { targetLinkDirs.add("/usr/lib/dir" + i); // every other dir has BT } long slowOps = slowGetDirectories(orderedDirs, targetLinkDirs); long fastOps = fastGetDirectories(orderedDirs, targetLinkDirs); double ratio = (double) slowOps / fastOps; total++; System.out.printf("N=%4d slow=%8d fast=%6d ratio=%.1fx%n", N, slowOps, fastOps, ratio); // At N=1000: slow ~ N*M/2 = 250000, fast ~ 3N/2 = 1500 → >100x assert ratio > 5.0 : "Expected slow/fast ratio > 5, got " + ratio; passed++; } // Correctness: both produce same result List dirs = Arrays.asList("/a", "/b", "/c"); List targets = Arrays.asList("/b"); // Just verify no crash and ops make sense long s = slowGetDirectories(dirs, targets); long f = fastGetDirectories(dirs, targets); assert s > 0 && f > 0; passed++; total++; System.out.printf("%d/%d PASS%n", passed, total); } }