java-topology/defects/weechat/patch/weechat-0003-irc-channel-search-hashmap.md
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

3.4 KiB
Raw Blame History

weechat-0003 — irc_channel_search O(C) linked-list scan — no hash index

Ecosystem

weechat (C)

Severity

MEDIUM — hot path: irc_channel_search() is called ~30+ times per IRC protocol message in irc-protocol.c (JOIN, PART, KICK, MODE, TOPIC, PRIVMSG, etc.)

Location

src/plugins/irc/irc-channel.c

  • Function: irc_channel_search (~line 92): O(C) linear walk of server->channels

src/plugins/irc/irc-protocol.c

  • ~30+ call sites including: JOIN (~line 1560, 1587), PART (~line 1753), KICK (~line 1928), MODE (~line 2180), NICK (~line 2297), PRIVMSG (~line 3112), numeric 353/366/332 handlers, etc.

Description

irc_channel_search scans a linked list of all channels on a server to find a channel by name:

// irc-channel.c:92
struct t_irc_channel *
irc_channel_search (struct t_irc_server *server, const char *channel_name)
{
    struct t_irc_channel *ptr_channel;

    if (!server || !channel_name)
        return NULL;

    for (ptr_channel = server->channels; ptr_channel;
         ptr_channel = ptr_channel->next_channel)      // O(C) walk
    {
        if (irc_server_strcasecmp (server, ptr_channel->name, channel_name) == 0)
            return ptr_channel;
    }
    return NULL;
}

With C channels on a server, each call is O(C). In irc-protocol.c, this function is called ~30+ times across different protocol message handlers, each of which processes one message. The cost per message is O(C) per irc_channel_search call.

In extreme cases (e.g., a bot joined to thousands of channels, or an IRC network with large JOIN parameter lists), the cumulative cost per protocol event grows significantly.

The NICK handler at line ~2297 calls irc_channel_search once, then iterates over all C channels calling irc_nick_search (O(N) each) — that O(C×N) pattern is weechat-0001. The standalone irc_channel_search O(C) cost itself is weechat-0003.

Fix

Add a channels_hashtable to struct t_irc_server (channel_name → t_irc_channel*), mirroring the nicks_hashtable fix from weechat-0001:

--- a/src/plugins/irc/irc-server.h
+++ b/src/plugins/irc/irc-server.h
@@ struct t_irc_server {
    struct t_irc_channel *channels;
+   struct t_hashtable *channels_hashtable; /* channel_name(lower) → t_irc_channel* */

--- a/src/plugins/irc/irc-channel.c
+++ b/src/plugins/irc/irc-channel.c
 struct t_irc_channel *
 irc_channel_search (struct t_irc_server *server, const char *channel_name)
 {
-    for (ptr_channel = server->channels; ptr_channel; ...)
-        if (irc_server_strcasecmp (...) == 0) return ptr_channel;
+    if (server->channels_hashtable) {
+        char lower[512];
+        snprintf(lower, sizeof(lower), "%s", channel_name);
+        /* lowercase using irc_server_casemapping */
+        return weechat_hashtable_get(server->channels_hashtable, lower);
+    }
+    /* fallback to linear scan */
+    ...
}

Complexity

Variant Cost per lookup
Before O(C) — linear scan through all channels
After O(1) — hash table lookup
Speedup C× — at C=1000 channels: 1000×

Notes

  • IRC servers typically allow users to join 100-2000 channels
  • Bots joining many channels (monitoring, bridging) are common and hit this hard
  • The t_irc_server.channels list is modified on JOIN/PART; the hashtable must be kept in sync in irc_channel_new() and irc_channel_free()
  • weechat-0001 fixed nicks_hashtable; this defect is the parallel issue for channel lookup on the server