java-topology/whitepaper/outreach/0ad-0002.md
russell@unturf.com 9a78d1afbe feat: add 15 outreach docs (15 defects) for 1-patch projects
0ad (4), aranym, ardour, argo-cd, aria2, azahar, bcoin, bind9,
btcpayserver (3), bullet3. Mix of CWE-407 and CWE-312.
2026-04-14 14:33:17 -04:00

2.9 KiB
Raw Blame History

0 A.D. — CWE-407 Disclosure Brief (0ad-0002)

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

Finding

One O(n²) defect in 0 A.D.'s range manager. The modified entities tracking uses std::vector with std::find for deduplication and membership testing, causing O(E*M) per-frame cost where E = total entities and M = modified entities.

The Defect

0ad-0002 (PATCHED — HIGH): source/simulation2/components/CCmpRangeManager.cpp:409

// In CCmpRangeManager — modified entity tracking:
std::vector<entity_id_t> m_ModifiedEntities;

// RequestVisibilityUpdate — O(M) scan before insert:
if (std::find(m_ModifiedEntities.begin(), m_ModifiedEntities.end(), ent)
    == m_ModifiedEntities.end())
    m_ModifiedEntities.push_back(ent);

// GetLosVisibility — O(M) scan per entity per player:
if (std::find(m_ModifiedEntities.begin(), m_ModifiedEntities.end(), entId)
    != m_ModifiedEntities.end())
    return ComputeLosVisibility(ent, player);

m_ModifiedEntities tracks which entities need visibility recalculation. RequestVisibilityUpdate fires per entity movement, scanning the entire vector before appending. GetLosVisibility scans the vector per entity per player for line-of-sight checks. With many moving entities, both paths become quadratic.

Complexity Proof

At M=500 modified entities, E=2000 total entities, P=8 players:

  • Defective: 500 insertions × average 250 comparisons + 2000 × 8 × 500 visibility checks = 8,125,000 comparisons per frame
  • Fixed: 500 O(1) insertions + 16,000 O(1) lookups = 16,500 operations per frame
  • ~490× op reduction per frame.

Impact

0 A.D. simulates line-of-sight visibility for all entities across all players every frame. The range manager defect compounds with entity count and player count, making large multiplayer matches with many moving units disproportionately slow.

The Fix

Replace std::vector<entity_id_t> with std::unordered_set<entity_id_t>:

// Before
std::vector<entity_id_t> m_ModifiedEntities;

// After
// CWE-407 fix: unordered_set for O(1) membership test.
std::unordered_set<entity_id_t> m_ModifiedEntities;

Serialization preserved via vector conversion for backward compatibility.

Patch

Fix available: defects/0ad-0002/patch/0ad-0002.patch

Single-file patch on CCmpRangeManager.cpp. Replaces vector with unordered_set, updates insert/find/iteration patterns, adds serialization compatibility layer.

What We Ask

A patch is ready for review.

  1. Confirm receipt and assign an issue reference (0ad/0ad or Wildfire Games Trac).
  2. Assess severity — this defect fires every frame, scaling with entity count × player count.
  3. Coordinate a disclosure date — we target 90 days from first contact.
  4. We will credit the 0 A.D. team in the public disclosure. Preferred acknowledgment format welcome.

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