0ad (4), aranym, ardour, argo-cd, aria2, azahar, bcoin, bind9, btcpayserver (3), bullet3. Mix of CWE-407 and CWE-312.
3.6 KiB
Bullet Physics (bullet3) — CWE-407 Disclosure Brief (bullet3-0001)
2026-04-13 · Patch available — awaiting upstream merge
Finding
One O(N²) defect in Bullet Physics's ghost object overlap tracking. btGhostObject::addOverlappingObjectInternal and removeOverlappingObjectInternal use findLinearSearch for membership testing on every broadphase callback, making per-tick pair updates quadratic in the number of overlapping objects.
The Defect
bullet3-0001 (PATCHED — HIGH): src/BulletCollision/CollisionDispatch/btGhostObject.cpp:32,44
// In btGhostObject::addOverlappingObjectInternal():
int index = m_overlappingObjects.findLinearSearch(otherObject);
if (index == m_overlappingObjects.size())
{
m_overlappingObjects.push_back(otherObject);
}
// In btGhostObject::removeOverlappingObjectInternal():
int index = m_overlappingObjects.findLinearSearch(otherObject);
if (index < m_overlappingObjects.size())
{
m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size() - 1];
m_overlappingObjects.pop_back();
}
m_overlappingObjects is a btAlignedObjectArray<btCollisionObject*>. findLinearSearch scans the entire array on every broadphase add/remove callback. Both btGhostObject and btPairCachingGhostObject exhibit the same pattern. With P overlapping objects, each tick costs O(P) per callback × P callbacks = O(P²) total.
Complexity Proof
At P=500 overlapping objects per ghost object at 60Hz:
- Defective: 500 × 250 average = 125,000 pointer comparisons per tick per ghost
- Fixed: 500 × O(1) hash lookups = 500 operations per tick per ghost
- ~250× op reduction per tick per ghost object.
Impact
Bullet Physics is used in games, robotics simulation (ROS/Gazebo), and scientific computing. Ghost objects serve as triggers, sensors, and area detectors. Any scene with many overlapping physics bodies (crowds, particle effects, explosion radii, sensor zones) hits the quadratic path every physics tick. The original source code contains a comment acknowledging this: "if this linearSearch becomes too slow (too many overlapping objects) we should add a more appropriate data structure."
The Fix
Add a btHashMap<btHashPtr, int> shadow index mapping object pointers to their array indices:
// Before
int index = m_overlappingObjects.findLinearSearch(otherObject);
// After
// CWE-407 fix: btHashMap for O(1) lookup instead of O(N) findLinearSearch.
btHashMap<btHashPtr, int> m_overlappingObjectsIndex;
if (m_overlappingObjectsIndex.find(btHashPtr(otherObject)) == NULL)
{
int index = m_overlappingObjects.size();
m_overlappingObjects.push_back(otherObject);
m_overlappingObjectsIndex.insert(btHashPtr(otherObject), index);
}
Removal uses swap-with-last and updates the moved element's index entry in the hash map.
Patch
Fix available: defects/bullet3/patch/bullet3-0001-ghost-object-overlapping-hashmap.patch
Two-file patch across btGhostObject.h and btGhostObject.cpp. Adds m_overlappingObjectsIndex hash map, updates all four add/remove methods (two in btGhostObject, two in btPairCachingGhostObject).
What We Ask
A patch is ready for review.
- Confirm receipt and assign a GitHub issue reference (bulletphysics/bullet3).
- Assess severity — fires every physics tick for every ghost object with overlaps.
- Coordinate a disclosure date — we target 90 days from first contact.
- We will credit the Bullet Physics team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.