bird-0003/0004 + frrouting-0003/0004: BGP community set ops O(N×M)/O(N²); OpenBGPD CLEAN; count 595→599
This commit is contained in:
parent
3f8c5e6d3e
commit
ff7bd27654
11 changed files with 671 additions and 4 deletions
189
defects/frrouting/unit/FrrCommunityUniqSortAlgorithmTest.java
Normal file
189
defects/frrouting/unit/FrrCommunityUniqSortAlgorithmTest.java
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Models FRRouting community_uniq_sort and ecommunity_include defects.
|
||||
*
|
||||
* frrouting-0003: community_uniq_sort O(N²) — contains check per element during dedup
|
||||
* frrouting-0004: ecommunity_include O(E1×E2) — nested loop cross-membership
|
||||
*
|
||||
* SLOW: O(N²) dedup / O(E1×E2) include
|
||||
* FAST: O(N log N) sort+dedup / O(E1+E2) HashSet
|
||||
*
|
||||
* CWE-407: bgpd/bgp_community.c:143, bgpd/bgp_ecommunity.c:1534
|
||||
*/
|
||||
public class FrrCommunityUniqSortAlgorithmTest {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// frrouting-0003: community_uniq_sort slow path
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static class SlowCommunitySort {
|
||||
long scanOps = 0;
|
||||
|
||||
boolean include(int[] arr, int n, int val) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
scanOps++;
|
||||
if (arr[i] == val) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** O(N²): include-check per element then qsort at end */
|
||||
int[] uniqSort(int[] input) {
|
||||
int[] result = new int[input.length];
|
||||
int size = 0;
|
||||
for (int val : input) {
|
||||
if (!include(result, size, val)) {
|
||||
result[size++] = val;
|
||||
}
|
||||
}
|
||||
int[] out = Arrays.copyOf(result, size);
|
||||
Arrays.sort(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
long ops(int[] input) { scanOps = 0; uniqSort(input); return scanOps; }
|
||||
}
|
||||
|
||||
static class FastCommunitySort {
|
||||
long scanOps = 0;
|
||||
|
||||
/** O(N log N): sort first, then linear dedup */
|
||||
int[] uniqSort(int[] input) {
|
||||
int[] sorted = Arrays.copyOf(input, input.length);
|
||||
Arrays.sort(sorted); // O(N log N) — counted implicitly
|
||||
// Count ops for linear dedup pass
|
||||
int out = 0;
|
||||
int[] result = new int[sorted.length];
|
||||
for (int i = 0; i < sorted.length; i++) {
|
||||
scanOps++;
|
||||
if (i == 0 || sorted[i] != sorted[i - 1]) {
|
||||
result[out++] = sorted[i];
|
||||
}
|
||||
}
|
||||
return Arrays.copyOf(result, out);
|
||||
}
|
||||
|
||||
long ops(int[] input) { scanOps = 0; uniqSort(input); return scanOps; }
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// frrouting-0004: ecommunity_include slow path
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static class SlowEcommunityInclude {
|
||||
long cmpOps = 0;
|
||||
|
||||
boolean include(long[] e1, long[] e2) {
|
||||
for (long v1 : e1) {
|
||||
for (long v2 : e2) {
|
||||
cmpOps++;
|
||||
if (v1 == v2) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
long ops(long[] e1, long[] e2) { cmpOps = 0; include(e1, e2); return cmpOps; }
|
||||
}
|
||||
|
||||
static class FastEcommunityInclude {
|
||||
long cmpOps = 0;
|
||||
|
||||
boolean include(long[] e1, long[] e2) {
|
||||
Set<Long> set = new HashSet<>();
|
||||
for (long v : e2) { set.add(v); cmpOps++; }
|
||||
for (long v : e1) {
|
||||
cmpOps++;
|
||||
if (set.contains(v)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
long ops(long[] e1, long[] e2) { cmpOps = 0; include(e1, e2); return cmpOps; }
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static int[] makeWithDups(int uniqueVals, int totalSize) {
|
||||
Random rng = new Random(42);
|
||||
int[] arr = new int[totalSize];
|
||||
for (int i = 0; i < totalSize; i++) arr[i] = rng.nextInt(uniqueVals);
|
||||
return arr;
|
||||
}
|
||||
|
||||
static long[] makeLong(int n, int offset) {
|
||||
long[] a = new long[n];
|
||||
for (int i = 0; i < n; i++) a[i] = offset + i;
|
||||
return a;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SlowCommunitySort slowSort = new SlowCommunitySort();
|
||||
FastCommunitySort fastSort = new FastCommunitySort();
|
||||
SlowEcommunityInclude slowInc = new SlowEcommunityInclude();
|
||||
FastEcommunityInclude fastInc = new FastEcommunityInclude();
|
||||
|
||||
int passed = 0, total = 0;
|
||||
|
||||
System.out.println("=== frrouting-0003: community_uniq_sort O(N²) ===");
|
||||
int[] sizes = {50, 100, 200, 500};
|
||||
for (int n : sizes) {
|
||||
int[] input = makeWithDups(n / 2, n); // ~50% dups
|
||||
long s = slowSort.ops(input);
|
||||
long f = fastSort.ops(input);
|
||||
double ratio = (double) s / Math.max(f, 1);
|
||||
total++;
|
||||
boolean ok = s > f && ratio >= 3.0;
|
||||
System.out.printf("N=%3d slow=%8d fast=%5d ratio=%6.1fx %s%n",
|
||||
n, s, f, ratio, ok ? "PASS" : "FAIL");
|
||||
if (ok) passed++;
|
||||
}
|
||||
|
||||
// Correctness: both produce same sorted unique result
|
||||
int[] input = makeWithDups(50, 100);
|
||||
int[] sr = slowSort.uniqSort(input);
|
||||
int[] fr = fastSort.uniqSort(input);
|
||||
total++;
|
||||
boolean correct1 = Arrays.equals(sr, fr);
|
||||
System.out.printf("uniqSort correctness: %s%n", correct1 ? "PASS" : "FAIL");
|
||||
if (correct1) passed++;
|
||||
|
||||
System.out.println("=== frrouting-0004: ecommunity_include O(E1×E2) ===");
|
||||
int[] esizes = {20, 50, 100, 200};
|
||||
for (int e : esizes) {
|
||||
long[] e1 = makeLong(e, 0);
|
||||
long[] e2 = makeLong(e, e); // disjoint — forces full scan
|
||||
long s = slowInc.ops(e1, e2);
|
||||
long f = fastInc.ops(e1, e2);
|
||||
double ratio = (double) s / Math.max(f, 1);
|
||||
total++;
|
||||
boolean ok = s > f && ratio >= 3.0;
|
||||
System.out.printf("E1=%3d E2=%3d slow=%8d fast=%5d ratio=%6.1fx %s%n",
|
||||
e, e, s, f, ratio, ok ? "PASS" : "FAIL");
|
||||
if (ok) passed++;
|
||||
}
|
||||
|
||||
// Correctness: include detects overlap
|
||||
long[] a = makeLong(50, 0), b = makeLong(50, 25); // overlap at 25-49
|
||||
total++;
|
||||
boolean correct2 = slowInc.include(a, b) == fastInc.include(a, b);
|
||||
System.out.printf("ecommunity_include correctness (overlap): %s%n",
|
||||
correct2 ? "PASS" : "FAIL");
|
||||
if (correct2) passed++;
|
||||
|
||||
total++;
|
||||
long[] c = makeLong(50, 100); // disjoint
|
||||
boolean correct3 = slowInc.include(a, c) == fastInc.include(a, c);
|
||||
System.out.printf("ecommunity_include correctness (disjoint): %s%n",
|
||||
correct3 ? "PASS" : "FAIL");
|
||||
if (correct3) passed++;
|
||||
|
||||
System.out.printf("%n%d/%d PASS%n", passed, total);
|
||||
if (passed < total) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue