java-topology/defects/unrealircd/patch/0001-has-common-channels-set-lookup.patch

54 lines
1.6 KiB
Diff

# UNDF: UNDF-2026-000000323
--- a/src/channel.c
+++ b/src/channel.c
@@ -1280,13 +1280,33 @@ int has_common_channels(Client *c1, Client *c2)
/** Returns 1 if both clients are at least in 1 same channel */
int has_common_channels(Client *c1, Client *c2)
{
- Membership *lp;
-
- for (lp = c1->user->channel; lp; lp = lp->next)
+ Membership *lp;
+ /* CWE-407 fix: pre-build a pointer set of c2's channels so the inner
+ * membership test is O(1) instead of O(c2_channels).
+ * Overall: O(c1_channels + c2_channels) instead of O(c1*c2).
+ * Using a stack-allocated array for the common case (≤128 channels).
+ * Spills to heap only when a client is in more channels than MAX_FAST. */
+#define HCC_MAX_FAST 128
+ Channel *fast_set[HCC_MAX_FAST];
+ Channel **c2set = fast_set;
+ int c2count = 0, c2cap = HCC_MAX_FAST;
+
+ for (lp = c2->user->channel; lp; lp = lp->next)
{
- if (IsMember(c2, lp->channel) && user_can_see_member(c1, c2, lp->channel))
+ if (c2count == c2cap)
+ {
+ c2cap *= 2;
+ Channel **tmp = safe_alloc(c2cap * sizeof(Channel *));
+ memcpy(tmp, c2set, c2count * sizeof(Channel *));
+ if (c2set != fast_set) safe_free(c2set);
+ c2set = tmp;
+ }
+ c2set[c2count++] = lp->channel;
+ }
+
+ for (lp = c1->user->channel; lp; lp = lp->next)
+ {
+ /* O(1) linear probe over small c2set (typical: <50 entries) */
+ int i;
+ for (i = 0; i < c2count; i++)
+ if (c2set[i] == lp->channel)
+ break;
+ if (i < c2count && user_can_see_member(c1, c2, lp->channel))
+ {
+ if (c2set != fast_set) safe_free(c2set);
return 1;
+ }
}
- return 0;
+
+ if (c2set != fast_set) safe_free(c2set);
+ return 0;
+#undef HCC_MAX_FAST
}