Batch 9 (15): bun, bzflag (3), cake_wallet (4), calligra, caprice32 (2), cataclysm (3), cemu Batch 10 (15): cemu-0002, citra, clickhouse-java, cmake (3), cocos2d (3), conduit, cura (2), curaengine, clamav, contiki
2.9 KiB
Cocos2d-x — CWE-407 Disclosure Brief (cocos2d-0001)
2026-04-13 · Patch available — awaiting upstream merge
Finding
One O(n²) defect in Cocos2d-x in the event dispatcher system. std::find() over _toRemovedListeners (a std::vector<EventListener*>) fires on every listener removal and every listener cleanup pass. Patched.
The Defects
cocos2d-0001 (PATCHED — HIGH): cocos/base/CCEventDispatcher.cpp:607 and CCEventDispatcher.h
// In removeEventListener — fires on every listener removal:
if (std::find(_toRemovedListeners.begin(), _toRemovedListeners.end(), listener)
!= _toRemovedListeners.end()) // O(R) linear scan
return;
_toRemovedListeners is std::vector<EventListener*>. Three call sites use std::find() for membership checks: removeEventListener() (guards against double-remove), and two locations in updateListeners() that clean up removed listeners from scene-graph and fixed-priority lists.
During event dispatch with many listener additions and removals per frame, the vector grows and each std::find() costs O(R) where R = pending removals. Total cost per frame: O(E × R) where E = events dispatched.
Complexity Proof
At R=100 pending removals, E=50 events per frame:
- Defective: 50 × 100 = 5,000 comparisons per frame + cleanup passes
- Fixed: 50 × 1 = 50 hash lookups
- 100× op reduction per frame.
Impact
Cocos2d-x powers thousands of mobile and desktop games worldwide. The event dispatcher handles touch input, keyboard events, physics callbacks, and custom game events. Games with many interactive objects (puzzle games with hundreds of tiles, strategy games with many units, UI-heavy games) create and destroy event listeners frequently. Every frame that processes events pays the linear scan cost.
The Fix
Replace std::vector<EventListener*> with std::unordered_set<EventListener*>:
// Before
std::vector<EventListener*> _toRemovedListeners;
std::find(_toRemovedListeners.begin(), _toRemovedListeners.end(), listener)
_toRemovedListeners.push_back(l);
// After — O(1) lookup, insert, erase
std::unordered_set<EventListener*> _toRemovedListeners;
_toRemovedListeners.count(listener)
_toRemovedListeners.insert(l);
Patch
Fix available: defects/cocos2d-0001/patch/cocos2d-0001.patch
Two-file patch across CCEventDispatcher.h and CCEventDispatcher.cpp.
Unit test: pass. 100× op reduction at 100 pending removals.
What We Ask
A patch is ready for review.
- Confirm receipt and assign a GitHub issue reference (cocos2d/cocos2d-x).
- Assess severity — fires on every event dispatch frame with listener churn.
- Coordinate a disclosure date — we are targeting 90 days from first contact.
- We will credit the Cocos2d-x team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.