java-topology/defects/weechat/unit/WeechatChannelSearchTest.java
russell@unturf.com ba818693db nmap-0002 + haproxy-0004 + nginx-0004 + weechat-0003 + zeek-0002 + curl-0004: 6 new CWE-407 defects in network tools; count 693→699
nmap-0002:     nmap.cc merge_port_lists O(N²) port dedup → unordered_set O(N); ~65000x at max range
haproxy-0004:  http_ana.c http_capture_headers O(H×C) cap_hdr walk per request → pre-built HashMap O(H)
nginx-0004:    ngx_http_upstream_keepalive_module.c keepalive_get_peer O(C) sockaddr scan per upstream request → HashMap O(1)
weechat-0003:  irc-channel.c irc_channel_search O(C) linked-list scan per message handler → channels_hashtable O(1)
zeek-0002:     Attr.cc Attributes::AddAttrs O(A²) triple-Find/RemoveAttr per attr → unordered_map index O(A)
curl-0004:     mime.c search_header O(P×H) 3x per part per mime_add_headers → pre-indexed header name set O(P)
2026-03-29 22:22:11 -04:00

114 lines
4.2 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package unit;
import java.util.*;
/**
* weechat-0003 — CWE-407: irc_channel_search O(C) linked-list scan, no hash index
*
* Models src/plugins/irc/irc-channel.c irc_channel_search():
* Slow: linear walk of server->channels linked list → O(C)
* called ~30+ times per IRC protocol message
* Fast: HashMap<lowerName, channel> → O(1) per lookup
*
* Impact: bots/clients joined to hundreds of channels see O(C × M) per message
* where C = channels, M = channel search calls per message handler.
*/
public class WeechatChannelSearchTest {
static class IrcChannel {
final String name;
IrcChannel next;
IrcChannel(String name) { this.name = name.toLowerCase(); }
}
static class IrcServer {
IrcChannel channels; // linked list head (slow)
int channelCount;
final Map<String, IrcChannel> channelsMap = new HashMap<>(); // fast
}
// Build linked list of C channels
static void buildServer(IrcServer server, int C) {
server.channels = null;
server.channelCount = C;
for (int i = C - 1; i >= 0; i--) {
IrcChannel ch = new IrcChannel("#channel" + i);
ch.next = server.channels;
server.channels = ch;
server.channelsMap.put(ch.name, ch);
}
}
// --- SLOW: O(C) linear scan (defect) ---
static IrcChannel channelSearchSlow(IrcServer server, String name) {
String lower = name.toLowerCase();
for (IrcChannel ch = server.channels; ch != null; ch = ch.next) {
if (ch.name.equals(lower)) return ch;
}
return null;
}
// --- FAST: O(1) hash lookup (fix) ---
static IrcChannel channelSearchFast(IrcServer server, String name) {
return server.channelsMap.get(name.toLowerCase());
}
// Simulate a protocol message handler that calls irc_channel_search N times
static long simulateMessageHandlerSlow(IrcServer server, String[] targets, int callsPerTarget) {
long ops = 0;
for (String target : targets) {
for (int i = 0; i < callsPerTarget; i++) {
// each channelSearchSlow = O(C) — count worst-case ops
String lower = target.toLowerCase();
for (IrcChannel ch = server.channels; ch != null; ch = ch.next) {
ops++;
if (ch.name.equals(lower)) break;
}
}
}
return ops;
}
static long simulateMessageHandlerFast(IrcServer server, String[] targets, int callsPerTarget) {
long ops = 0;
for (String target : targets) {
for (int i = 0; i < callsPerTarget; i++) {
ops++; // O(1) hash lookup
server.channelsMap.get(target.toLowerCase());
}
}
return ops;
}
public static void main(String[] args) {
System.out.println("weechat-0003 CWE-407: irc_channel_search O(C) vs O(1)");
System.out.println("=======================================================");
IrcServer server = new IrcServer();
// Parameters: C channels, M=3 search calls per message handler (conservative)
int[][] params = { {100, 3}, {500, 5}, {1000, 10} };
for (int[] p : params) {
int C = p[0], callsPerMsg = p[1];
buildServer(server, C);
// Simulate 100 incoming IRC messages each needing callsPerMsg channel lookups
String[] targets = new String[100];
for (int i = 0; i < 100; i++)
targets[i] = "#channel" + (i % C); // random channels
long slowOps = simulateMessageHandlerSlow(server, targets, callsPerMsg);
long fastOps = simulateMessageHandlerFast(server, targets, callsPerMsg);
double ratio = (double) slowOps / fastOps;
System.out.printf(" C=%4d channels, %d lookups/msg, 100 msgs: slow=%,7d ops fast=%,5d ops speedup=%.0fx%n",
C, callsPerMsg, slowOps, fastOps, ratio);
assert ratio >= (double) C / 4 :
"Expected speedup >= " + (C/4) + "x but got " + ratio + " (C=" + C + ")";
}
System.out.println("\nPASS");
}
}