0ad (4), aranym, ardour, argo-cd, aria2, azahar, bcoin, bind9, btcpayserver (3), bullet3. Mix of CWE-407 and CWE-312.
2.9 KiB
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.
- Confirm receipt and assign an issue reference (0ad/0ad or Wildfire Games Trac).
- Assess severity — this defect fires every frame, scaling with entity count × player count.
- Coordinate a disclosure date — we target 90 days from first contact.
- 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.