java-topology/defects/bullet3/patch/bullet3-0001-ghost-object-overlapping-hashmap.patch

104 lines
4.3 KiB
Diff

# UNDF: UNDF-2026-000000603
# UNDF: (leave blank)
--- a/src/BulletCollision/CollisionDispatch/btGhostObject.h
+++ b/src/BulletCollision/CollisionDispatch/btGhostObject.h
@@ -19,6 +19,7 @@
#include "btCollisionObject.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h"
#include "LinearMath/btAlignedAllocator.h"
+#include "LinearMath/btHashMap.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "btCollisionWorld.h"
@@ -36,6 +37,12 @@ btGhostObject : public btCollisionObject
protected:
btAlignedObjectArray<btCollisionObject*> m_overlappingObjects;
+ // O(1) membership index: maps btCollisionObject* pointer -> index in m_overlappingObjects.
+ // Eliminates O(N) findLinearSearch on every broadphase add/remove callback,
+ // turning the per-tick pair-update loop from O(N²) to O(N). CWE-407.
+ btHashMap<btHashPtr, int> m_overlappingObjectsIndex;
+
public:
btGhostObject();
--- a/src/BulletCollision/CollisionDispatch/btGhostObject.cpp
+++ b/src/BulletCollision/CollisionDispatch/btGhostObject.cpp
@@ -32,10 +32,12 @@ void btGhostObject::addOverlappingObjectInternal(btBroadphaseProxy* otherProxy,
{
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
btAssert(otherObject);
- ///if this linearSearch becomes too slow (too many overlapping objects) we should add a more appropriate data structure
- int index = m_overlappingObjects.findLinearSearch(otherObject);
- if (index == m_overlappingObjects.size())
- {
- //not found
+ // O(1) hash lookup replaces O(N) findLinearSearch. CWE-407.
+ if (m_overlappingObjectsIndex.find(btHashPtr(otherObject)) == NULL)
+ {
+ int index = m_overlappingObjects.size();
m_overlappingObjects.push_back(otherObject);
+ m_overlappingObjectsIndex.insert(btHashPtr(otherObject), index);
}
}
@@ -44,11 +46,16 @@ void btGhostObject::removeOverlappingObjectInternal(btBroadphaseProxy* otherProx
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
btAssert(otherObject);
- int index = m_overlappingObjects.findLinearSearch(otherObject);
- if (index < m_overlappingObjects.size())
+ int* indexPtr = m_overlappingObjectsIndex.find(btHashPtr(otherObject));
+ if (indexPtr != NULL)
{
- m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size() - 1];
+ int index = *indexPtr;
+ int lastIndex = m_overlappingObjects.size() - 1;
+ if (index != lastIndex)
+ {
+ // Swap with last; update the moved element's index entry.
+ btCollisionObject* movedObject = m_overlappingObjects[lastIndex];
+ m_overlappingObjects[index] = movedObject;
+ m_overlappingObjectsIndex.insert(btHashPtr(movedObject), index);
+ }
m_overlappingObjects.pop_back();
+ m_overlappingObjectsIndex.remove(btHashPtr(otherObject));
}
}
@@ -68,9 +75,12 @@ void btPairCachingGhostObject::addOverlappingObjectInternal(btBroadphaseProxy* o
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
btAssert(otherObject);
- int index = m_overlappingObjects.findLinearSearch(otherObject);
- if (index == m_overlappingObjects.size())
- {
+ if (m_overlappingObjectsIndex.find(btHashPtr(otherObject)) == NULL)
+ {
+ int index = m_overlappingObjects.size();
m_overlappingObjects.push_back(otherObject);
+ m_overlappingObjectsIndex.insert(btHashPtr(otherObject), index);
m_hashPairCache->addOverlappingPair(actualThisProxy, otherProxy);
}
}
@@ -82,11 +92,19 @@ void btPairCachingGhostObject::removeOverlappingObjectInternal(btBroadphaseProxy
btAssert(actualThisProxy);
btAssert(otherObject);
- int index = m_overlappingObjects.findLinearSearch(otherObject);
- if (index < m_overlappingObjects.size())
+ int* indexPtr = m_overlappingObjectsIndex.find(btHashPtr(otherObject));
+ if (indexPtr != NULL)
{
- m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size() - 1];
+ int index = *indexPtr;
+ int lastIndex = m_overlappingObjects.size() - 1;
+ if (index != lastIndex)
+ {
+ btCollisionObject* movedObject = m_overlappingObjects[lastIndex];
+ m_overlappingObjects[index] = movedObject;
+ m_overlappingObjectsIndex.insert(btHashPtr(movedObject), index);
+ }
m_overlappingObjects.pop_back();
+ m_overlappingObjectsIndex.remove(btHashPtr(otherObject));
m_hashPairCache->removeOverlappingPair(actualThisProxy, otherProxy, dispatcher);
}
}