java-topology/whitepaper/outreach/xonotic-0004.md
russell@unturf.com 6784cdf1cf feat: add 39 outreach docs (batches 6-8)
Batch 6 (9): dolibarr, jitsi-videobridge, zed, tryton, suricata,
  strawberry, zulip, zesarux, zephyr
Batch 7 (15): xonotic (4), xash3d (3), xenia, xtuple, zabbix (2),
  zathura, zebra, yabause, zephyr-0001
Batch 8 (15): woodpecker (2), wine (4), widelands (3), wesnoth (3),
  wekan (3)

Mix of CWE-407 and CWE-312.
2026-04-14 17:06:28 -04:00

2.6 KiB
Raw Permalink Blame History

Xonotic (DarkPlaces) — CWE-407 Disclosure Brief (xonotic-0004)

2026-04-13 · Patch available — awaiting upstream merge

Finding

One O(N²) defect in DarkPlaces sound name lookup. S_FindName traverses a linked list of all known sound effects on every sound reference, making each lookup O(N) where N = total loaded sounds. The existing code contains a TODO comment: "TODO: hash table search?".

The Defect

xonotic-0004 (PATCHED — MEDIUM): snd_main.c:922

// In S_FindName() — fires on every sound reference:
// TODO: hash table search?
for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
    if(!strcmp (sfx->name, name))
        return sfx;

known_sfx is a singly-linked list of all loaded sfx_t entries. Every sound playback, precache, or reference calls S_FindName, which walks the entire list via strcmp. As the game loads more sounds, every subsequent lookup grows linearly.

Complexity Proof

At N=300 loaded sounds, L=1000 lookups per map load:

  • Defective: 1000 × 150 average = 150,000 string comparisons
  • Fixed: 1000 × O(1) hash lookups = 1,000 operations
  • ~150x op reduction.

Impact

DarkPlaces loads sounds throughout gameplay (not just at map load). Every weapon fire, footstep, and ambient trigger calls S_FindName. Games with large sound libraries (Xonotic ships with hundreds of sound files) pay this cost on every audio event. The engine developers themselves identified this as a candidate for optimization (the TODO comment).

The Fix

Add a hash table (sfx_hashtable[256]) with per-sfx chain pointers for O(1) average lookup:

// Before
// TODO: hash table search?
for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
    if(!strcmp(sfx->name, name)) return sfx;

// After
// CWE-407 fix: hash table replaces O(N) linked list scan.
unsigned hashkey = S_NameHash(name);
for (sfx = sfx_hashtable[hashkey]; sfx != NULL; sfx = sfx->hashnext)
    if (!strcmp(sfx->name, name)) return sfx;

Patch

Fix available: defects/xonotic-0004/patch/xonotic-0004.patch

Two-file patch across snd_main.c and snd_main.h. Adds hashnext pointer to sfx_t struct, hash table array, and hash function.

What We Ask

A patch is ready for review.

  1. Confirm receipt and assign a GitHub issue reference (xonotic/darkplaces).
  2. Assess severity — fires on every sound playback event, scaling with loaded sound count.
  3. Coordinate a disclosure date — we target 90 days from first contact.
  4. We will credit the Xonotic/DarkPlaces team in the public disclosure. Preferred acknowledgment format welcome.

Contact: see cover email. This brief is confidential until coordinated disclosure.