wave17 complete: systemd/emacs/vim/qemu/tcl/kafka-0007/spark-0004 + 559/240
This commit is contained in:
parent
4221966e66
commit
cce7ec653a
32 changed files with 3007 additions and 5 deletions
174
defects/systemd/unit/SystemdStrvExtendDedupTest.java
Normal file
174
defects/systemd/unit/SystemdStrvExtendDedupTest.java
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit test: systemd-0001
|
||||
*
|
||||
* strv_extend_strv() with filter_duplicates=true calls strv_contains() (O(N)
|
||||
* linear scan) inside a loop over every element of the input array.
|
||||
* Total cost: O(N^2).
|
||||
*
|
||||
* Fix: replace the growing-array scan with a HashSet for O(1) membership.
|
||||
*/
|
||||
public class SystemdStrvExtendDedupTest {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// SLOW path: simulates strv_extend_strv with filter_duplicates
|
||||
// Uses List.contains() (O(N)) inside the append loop — O(N^2) total.
|
||||
// -----------------------------------------------------------------------
|
||||
static long slowExtendDedup(List<String> target, String[] source) {
|
||||
long ops = 0;
|
||||
for (String s : source) {
|
||||
// O(|target|) scan — strv_contains / strv_find equivalent
|
||||
ops += target.size(); // count every comparison in the scan
|
||||
if (!target.contains(s)) {
|
||||
target.add(s);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// FAST path: dedup via HashSet — O(N) total.
|
||||
// -----------------------------------------------------------------------
|
||||
static long fastExtendDedup(List<String> target, String[] source) {
|
||||
long ops = 0;
|
||||
Set<String> seen = new HashSet<>(target);
|
||||
for (String s : source) {
|
||||
ops++; // one hash lookup
|
||||
if (seen.add(s)) {
|
||||
target.add(s);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -----------------------------------------------------------------------
|
||||
static String[] makeUnique(int n) {
|
||||
String[] a = new String[n];
|
||||
for (int i = 0; i < n; i++) a[i] = "unit-" + i + ".service";
|
||||
return a;
|
||||
}
|
||||
|
||||
static String[] makeDuplicates(int n) {
|
||||
// All the same string — worst case for dedup scan
|
||||
String[] a = new String[n];
|
||||
Arrays.fill(a, "duplicate.service");
|
||||
return a;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Tests
|
||||
// -----------------------------------------------------------------------
|
||||
static int pass = 0;
|
||||
static int fail = 0;
|
||||
|
||||
static void check(String name, boolean condition) {
|
||||
if (condition) {
|
||||
System.out.println("PASS: " + name);
|
||||
pass++;
|
||||
} else {
|
||||
System.out.println("FAIL: " + name);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
static void testUniqueStrings(int n) {
|
||||
// Unique strings: slow does N*(N-1)/2 comparisons, fast does N.
|
||||
List<String> slowTarget = new ArrayList<>();
|
||||
List<String> fastTarget = new ArrayList<>();
|
||||
String[] source = makeUnique(n);
|
||||
|
||||
long slowOps = slowExtendDedup(slowTarget, source);
|
||||
long fastOps = fastExtendDedup(fastTarget, source);
|
||||
|
||||
check("unique[N=" + n + "]: slow result size == fast result size",
|
||||
slowTarget.size() == fastTarget.size());
|
||||
check("unique[N=" + n + "]: result contains all source elements",
|
||||
slowTarget.containsAll(Arrays.asList(source)));
|
||||
|
||||
double ratio = (double) slowOps / fastOps;
|
||||
System.out.printf(" ops: slow=%d fast=%d ratio=%.1fx%n", slowOps, fastOps, ratio);
|
||||
check("unique[N=" + n + "]: slowOps/fastOps >= 5x", ratio >= 5.0);
|
||||
}
|
||||
|
||||
static void testAllDuplicates(int n) {
|
||||
// Growing target: n elements already present, then n more unique elements appended.
|
||||
// The slow path scans all n existing entries for each new element: O(N^2).
|
||||
// The fast path does O(1) hash lookup per new element.
|
||||
List<String> slowTarget = new ArrayList<>();
|
||||
List<String> fastTarget = new ArrayList<>();
|
||||
// Pre-fill target with n entries (these already exist, won't be added again)
|
||||
for (int i = 0; i < n; i++) {
|
||||
slowTarget.add("existing-" + i + ".service");
|
||||
fastTarget.add("existing-" + i + ".service");
|
||||
}
|
||||
// Source: n new unique strings (none are duplicates of target, so all get added)
|
||||
String[] source = new String[n];
|
||||
for (int i = 0; i < n; i++) source[i] = "new-" + i + ".service";
|
||||
|
||||
long slowOps = slowExtendDedup(slowTarget, source);
|
||||
long fastOps = fastExtendDedup(fastTarget, source);
|
||||
|
||||
check("growing-target[N=" + n + "]: both add all N new elements",
|
||||
slowTarget.size() == 2 * n && fastTarget.size() == 2 * n);
|
||||
check("growing-target[N=" + n + "]: slow and fast agree",
|
||||
slowTarget.equals(fastTarget));
|
||||
|
||||
double ratio = (double) slowOps / fastOps;
|
||||
System.out.printf(" ops: slow=%d fast=%d ratio=%.1fx%n", slowOps, fastOps, ratio);
|
||||
check("growing-target[N=" + n + "]: slowOps/fastOps >= 5x", ratio >= 5.0);
|
||||
}
|
||||
|
||||
static void testMixed(int n) {
|
||||
// Half unique, half duplicate
|
||||
List<String> slowTarget = new ArrayList<>();
|
||||
List<String> fastTarget = new ArrayList<>();
|
||||
String[] source = new String[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
source[i] = (i % 2 == 0) ? "even-" + i + ".service" : "odd.service";
|
||||
}
|
||||
|
||||
long slowOps = slowExtendDedup(slowTarget, source);
|
||||
long fastOps = fastExtendDedup(fastTarget, source);
|
||||
|
||||
check("mixed[N=" + n + "]: slow and fast agree on result",
|
||||
slowTarget.equals(fastTarget));
|
||||
|
||||
double ratio = (double) slowOps / fastOps;
|
||||
System.out.printf(" ops: slow=%d fast=%d ratio=%.1fx%n", slowOps, fastOps, ratio);
|
||||
check("mixed[N=" + n + "]: slowOps/fastOps >= 5x", ratio >= 5.0);
|
||||
}
|
||||
|
||||
static void testCorrectnessSmall() {
|
||||
// Correctness: strv_extend_strv({"a","b"}, {"b","c","d"}, true) -> {"a","b","c","d"}
|
||||
List<String> slowT = new ArrayList<>(Arrays.asList("a", "b"));
|
||||
List<String> fastT = new ArrayList<>(Arrays.asList("a", "b"));
|
||||
String[] src = {"b", "c", "d"};
|
||||
slowExtendDedup(slowT, src);
|
||||
fastExtendDedup(fastT, src);
|
||||
List<String> expected = Arrays.asList("a", "b", "c", "d");
|
||||
check("correctness: slow result", slowT.equals(expected));
|
||||
check("correctness: fast result", fastT.equals(expected));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Main
|
||||
// -----------------------------------------------------------------------
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== systemd-0001: strv_extend_strv dedup O(N^2) → O(N) ===");
|
||||
|
||||
testCorrectnessSmall();
|
||||
testUniqueStrings(500);
|
||||
testAllDuplicates(500);
|
||||
testMixed(500);
|
||||
testUniqueStrings(1000);
|
||||
|
||||
System.out.println();
|
||||
System.out.printf("%d/%d PASS%n", pass, pass + fail);
|
||||
if (fail > 0) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue