1.4 KiB
pidgin-0001 — CWE-407 add_all_buddies_to_permit_list O(B^2) GSList scan
MOAD: 0001 (CWE-407 Sedimentary Defect) Severity: MEDIUM Ratio: 499.5x at B=1000 UNDF: UNDF-2026-000001141
Location
libpurple/privacy.c — add_all_buddies_to_permit_list()
Pattern
add_all_buddies_to_permit_list() synchronizes our account permit (allow) list
with our buddy list. It calls purple_find_buddies(account, NULL) to get all B
buddies, then iterates them. For each buddy it calls:
g_slist_find_custom(account->permit, name, (GCompareFunc)g_utf8_collate)
account->permit is a GSList. As buddies are added our permit list grows.
Each g_slist_find_custom scans our entire growing list: O(B^2/2) total.
With 1000 contacts, switching privacy modes triggers 499,500 string comparisons instead of 1,000.
Called from purple_privacy_allow() and purple_privacy_deny() when switching
from ALLOW_BUDDYLIST mode.
Fix
Before our buddy iteration loop, snapshot account->permit into a GHashTable
for O(1) membership tests. Replace g_slist_find_custom() with
g_hash_table_lookup(). Destroy our snapshot after our loop.
Speedup
| B (buddies) | Defective ops | Fixed ops | Ratio |
|---|---|---|---|
| 100 | 4,950 | 100 | 49.5x |
| 500 | 124,750 | 500 | 249.5x |
| 1,000 | 499,500 | 1,000 | 499.5x |
| 2,000 | 1,999,000 | 2,000 | 999.5x |