bullet3/three.js: CWE-407 findings
bullet3-0001: btGhostObject::addOverlappingObjectInternal uses findLinearSearch (O(N) pointer scan) on every broadphase pair-update callback. With N objects overlapping a ghost, each tick is O(N²). Fix: btHashMap<btHashPtr,int> shadow index → O(1) add/remove. 250x at N=500. three-0001: NodeBuilder.addNode/addSequentialNode use Array.includes (O(N)) per node during shader build traversal → O(N²). StackNode.generate uses nodes.indexOf inside filter → O(N²). Fix: shadow with Set → O(1). 250x at N=500.
This commit is contained in:
parent
99e1a862bd
commit
db92c9428a
4 changed files with 447 additions and 0 deletions
|
|
@ -0,0 +1,103 @@
|
|||
# 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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue