java-topology/defects/nagioscore-0001/test/NagiosCoreNotificationDedupTest.java

106 lines
3.9 KiB
Java

import java.util.*;
/**
* CWE-407 unit test for Nagios Core nagioscore-0001:
* find_notification() linked-list linear scan for contact dedup in
* add_notification() — O(C²) where C = number of notification contacts.
*
* Defect: base/notifications.c add_notification() calls find_notification()
* which walks the entire notification linked list to check for duplicates.
* Each add is O(N), called N times = O(N²).
*
* Fix: Use a HashSet (dkhash_table in C) for O(1) membership check.
*/
public class NagiosCoreNotificationDedupTest {
// --- DEFECTIVE: linked-list linear scan for dedup ---
static LinkedList<String> notificationListDefective = new LinkedList<>();
static boolean findNotificationDefective(String contact) {
for (String c : notificationListDefective) {
if (c.equals(contact)) return true;
}
return false;
}
static int addNotificationDefective(String contact) {
if (findNotificationDefective(contact)) return 0; // already present
notificationListDefective.addFirst(contact);
return 1;
}
// --- FIXED: HashSet for O(1) dedup ---
static LinkedList<String> notificationListFixed = new LinkedList<>();
static HashSet<String> notificationHashFixed = new HashSet<>();
static int addNotificationFixed(String contact) {
if (notificationHashFixed.contains(contact)) return 0;
notificationListFixed.addFirst(contact);
notificationHashFixed.add(contact);
return 1;
}
static void reset() {
notificationListDefective.clear();
notificationListFixed.clear();
notificationHashFixed.clear();
}
public static void main(String[] args) {
int C = 2000; // number of contacts
// Generate unique contact names
String[] contacts = new String[C];
for (int i = 0; i < C; i++) {
contacts[i] = "contact_" + i;
}
// --- Defective path ---
reset();
long opsDefective = 0;
long startDef = System.nanoTime();
for (String contact : contacts) {
// Linear scan: O(current_size) per add
for (String c : notificationListDefective) {
opsDefective++;
if (c.equals(contact)) break;
}
notificationListDefective.addFirst(contact);
}
long defectiveNs = System.nanoTime() - startDef;
// --- Fixed path ---
reset();
long opsFixed = 0;
long startFix = System.nanoTime();
for (String contact : contacts) {
opsFixed++; // HashSet.contains is O(1)
if (!notificationHashFixed.contains(contact)) {
notificationListFixed.addFirst(contact);
notificationHashFixed.add(contact);
}
}
long fixedNs = System.nanoTime() - startFix;
double ratio = (double) opsDefective / Math.max(opsFixed, 1);
double speedup = (double) defectiveNs / Math.max(fixedNs, 1);
System.out.println("=== Nagios Core nagioscore-0001: notification dedup CWE-407 ===");
System.out.println("Contacts: " + C);
System.out.println("Defective ops: " + opsDefective);
System.out.println("Fixed ops: " + opsFixed);
System.out.println("Op ratio: " + String.format("%.1fx", ratio));
System.out.println("Defective time: " + (defectiveNs / 1_000_000) + " ms");
System.out.println("Fixed time: " + (fixedNs / 1_000_000) + " ms");
System.out.println("Speedup: " + String.format("%.1fx", speedup));
// Verify correctness
assert notificationListFixed.size() == C : "Fixed list should have all contacts";
// Verify O(N²) vs O(N)
boolean pass = ratio > 5.0;
System.out.println("RESULT: " + (pass ? "PASS" : "FAIL") +
" (ratio " + String.format("%.1f", ratio) + "x, threshold 5x)");
if (!pass) System.exit(1);
}
}