java-topology/defects/cmake/unit/AddSourceAlgorithm.java

89 lines
3.1 KiB
Java

package unit;
import java.util.*;
/**
* CWE-407 unit test: cmake-0004
* AddSource — O(n²) std::find_if per call in Unity build loop vs O(n) set guard.
*
* Simulates cmTarget::AddSource called in loop over unity_files:
* slow: scan Sources.Entries vector (find_if) for each add → O(n²)
* fast: use HashSet shadow, skip scan if already present → O(n)
*/
public class AddSourceAlgorithm {
// Slow: O(n^2) — find_if scan per AddSource call (mirrors TargetPropertyEntryFinder)
static long slowAddSources(List<String> unityFiles) {
long ops = 0;
List<String> sourcesEntries = new ArrayList<>();
for (String src : unityFiles) {
boolean found = false;
for (String existing : sourcesEntries) { // O(n) scan
ops++;
if (existing.equals(src)) {
found = true;
break;
}
}
if (!found) {
sourcesEntries.add(src);
}
}
return ops;
}
// Fast: HashSet shadow for O(1) check, O(n) total
static long fastAddSources(List<String> unityFiles) {
long ops = 0;
Set<String> sourcePathsSet = new HashSet<>();
List<String> sourcesEntries = new ArrayList<>();
for (String src : unityFiles) {
ops++;
if (sourcePathsSet.add(src)) {
sourcesEntries.add(src);
}
}
return ops;
}
public static void main(String[] args) {
int[] sizes = {200, 500, 1000, 2000};
int passed = 0, total = 0;
for (int S : sizes) {
// S unity source files, 20% duplicates (re-added after PCH generation)
List<String> unityFiles = new ArrayList<>(S + S / 5);
for (int i = 0; i < S; i++) {
unityFiles.add("/src/unity_" + i + ".cpp");
}
for (int i = 0; i < S / 5; i++) {
unityFiles.add("/src/unity_" + i + ".cpp"); // duplicate
}
long slowOps = slowAddSources(unityFiles);
long fastOps = fastAddSources(unityFiles);
double ratio = (double) slowOps / fastOps;
total++;
System.out.printf("S=%4d slow=%8d fast=%6d ratio=%.1fx%n",
S, slowOps, fastOps, ratio);
// At S=2000: slow is O(S^2/2) ~ 2M, fast is O(S) ~ 2000 → >100x
assert ratio > 20.0 : "Expected ratio > 20 at S=" + S + ", got " + ratio;
passed++;
}
// Correctness: same unique list preserved
List<String> input = Arrays.asList("a.cpp", "b.cpp", "a.cpp", "c.cpp");
List<String> slowOut = new ArrayList<>();
for (String s : input) {
if (!slowOut.contains(s)) slowOut.add(s);
}
Set<String> fastOut = new LinkedHashSet<>();
fastOut.addAll(input);
assert new ArrayList<>(fastOut).equals(slowOut) :
"Correctness: " + fastOut + " vs " + slowOut;
passed++; total++;
System.out.printf("%d/%d PASS%n", passed, total);
}
}