java-topology/whitepaper/outreach/xonotic-0001.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.9 KiB
Raw Permalink Blame History

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

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

Finding

One O(T²) defect in DarkPlaces engine texture lookup. Mod_Mesh_GetTexture performs a linear scan of data_textures on every draw call (every quad, character, HUD image), making total cost O(D×T) per frame where D = draw calls and T = loaded textures.

The Defect

xonotic-0001 (PATCHED — HIGH): model_shared.c:4476

// In Mod_Mesh_GetTexture() — fires per draw call:
for (i = 0, t = mod->data_textures; i < mod->num_textures; i++, t++)
    if (!strcmp(t->name, name) && t->mesh_drawflag == drawflag
        && t->mesh_defaulttexflags == defaulttexflags
        && t->mesh_defaultmaterialflags == defaultmaterialflags)
        return t;

data_textures grows as the game loads assets. Every UI draw call, every particle, every HUD element calls Mod_Mesh_GetTexture, which scans the entire texture array via strcmp. At 60fps with hundreds of draw calls per frame and hundreds of textures, this produces millions of unnecessary comparisons per second.

Complexity Proof

At T=200 textures, D=500 draw calls per frame:

  • Defective: 500 × 100 average = 50,000 string comparisons per frame
  • Fixed: 500 × O(1) hash lookups = 500 operations per frame
  • ~100x op reduction per frame. Fires every frame at 60+ fps.

Impact

Xonotic runs on DarkPlaces, a Quake-derived engine used by multiple games and mods. Every rendered frame pays this cost. Games with many textures (custom skins, map packs, HUD mods) scale worst. The defect directly affects frame time on texture-heavy maps.

The Fix

Add a hash table (mesh_texture_hashtable[256] + chain array) to model_t for O(1) average lookup:

// Before
for (i = 0, t = mod->data_textures; i < mod->num_textures; i++, t++)
    if (!strcmp(t->name, name) && ...) return t;

// After
// CWE-407 fix: hash table for O(1) texture lookup instead of O(T) linear scan.
hashkey = Mod_Mesh_TexHashKey(name, drawflag, defaulttexflags, defaultmaterialflags);
for (i = mod->mesh_texture_hashtable[hashkey]; i >= 0; i = mod->mesh_texture_hashnext[i])
    if (!strcmp(t->name, name) && ...) return t;

Patch

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

Two-file patch across model_shared.c and model_shared.h. Adds hash table fields to model_t struct and hash-based lookup 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 every frame on every draw call, scaling with texture 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.