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)
114 lines
4.2 KiB
Java
114 lines
4.2 KiB
Java
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");
|
||
}
|
||
}
|