java-topology/defects/weechat-0001/test/WeechatNicklistDedupTest.java
russell@unturf.com 128d349072 weechat-0001: nicklist dedup O(N^2) linear search on join
gui_nicklist_add_nick calls gui_nicklist_search_nick which linearly
scans the nick linked list for each add. Joining a 2000-user IRC
channel causes O(N^2) work. Fix: hash table for O(1) dedup. 999x ratio.
2026-03-31 07:37:50 -04:00

73 lines
2.4 KiB
Java

/**
* CWE-407 unit test for WeeChat gui-nicklist.c nick dedup defect.
*
* Defect: gui_nicklist_add_nick() calls gui_nicklist_search_nick() which
* performs O(N) linear scan through the nick linked list for each add.
* When bulk-adding N nicks (e.g., joining a large IRC channel with
* thousands of users), this yields O(N^2) total work.
*
* Fix: Maintain a hash table (name -> nick) per buffer for O(1) dedup.
*
* This test models the defect pattern in Java:
* - Defective: LinkedList + contains() for dedup on each add
* - Fixed: HashSet for O(1) dedup
*/
import java.util.*;
public class WeechatNicklistDedupTest {
/** Defective: linear scan through existing nicks for dedup */
static long defective(String[] nicks) {
LinkedList<String> nicklist = new LinkedList<>();
long ops = 0;
for (String nick : nicks) {
// gui_nicklist_search_nick_name: linear scan O(N)
ops += nicklist.size();
if (!nicklist.contains(nick)) {
nicklist.add(nick);
}
}
return ops;
}
/** Fixed: hash set for O(1) dedup */
static long fixed(String[] nicks) {
HashSet<String> nickSet = new HashSet<>();
LinkedList<String> nicklist = new LinkedList<>();
long ops = 0;
for (String nick : nicks) {
ops++; // O(1) hash lookup
if (nickSet.add(nick)) {
nicklist.add(nick);
}
}
return ops;
}
public static void main(String[] args) {
// Simulate joining a large IRC channel with 2000 unique users
int N = 2000;
String[] nicks = new String[N];
for (int i = 0; i < N; i++) {
nicks[i] = "user_" + i;
}
long defOps = defective(nicks);
long fixOps = fixed(nicks);
double ratio = (double) defOps / fixOps;
System.out.println("=== WeeChat gui-nicklist.c Nick Dedup Test ===");
System.out.println("Nicks added: " + N);
System.out.println("Defective ops: " + defOps);
System.out.println("Fixed ops: " + fixOps);
System.out.printf("Ratio (defective/fixed): %.1fx%n", ratio);
// Verify: defective should be significantly more expensive
boolean pass = ratio >= 5.0;
System.out.println("RESULT: " + (pass ? "PASS" : "FAIL")
+ " (ratio >= 5.0 required)");
if (!pass) System.exit(1);
}
}