63 lines
2.3 KiB
Diff
63 lines
2.3 KiB
Diff
# UNDF: UNDF-2026-000000084
|
|
--- a/modules/godot_physics_2d/godot_body_2d.h
|
|
+++ b/modules/godot_physics_2d/godot_body_2d.h
|
|
@@ -118,6 +118,7 @@ class GodotBody2D : public GodotCollisionObject2D {
|
|
// ...
|
|
|
|
Vector<AreaCMP> areas;
|
|
+ HashMap<RID, int> area_index; // O(1) area lookup by RID — shadow index for areas Vector
|
|
|
|
// ...
|
|
|
|
@@ -162,19 +163,24 @@ public:
|
|
_FORCE_INLINE_ void add_area(GodotArea2D *p_area) {
|
|
- int index = areas.find(AreaCMP(p_area));
|
|
- if (index > -1) {
|
|
- areas.write[index].refCount += 1;
|
|
+ // FIX godot-0002: was areas.find() — O(n) linear scan, CWE-407
|
|
+ // areas.find() scans entire Vector per call from GodotAreaPair2D::pre_solve().
|
|
+ // area_index provides O(1) lookup by RID.
|
|
+ RID rid = p_area->get_self();
|
|
+ HashMap<RID, int>::Iterator it = area_index.find(rid);
|
|
+ if (it != area_index.end()) {
|
|
+ areas.write[it->value].refCount += 1;
|
|
} else {
|
|
- areas.ordered_insert(AreaCMP(p_area));
|
|
+ int pos = areas.size();
|
|
+ areas.ordered_insert(AreaCMP(p_area));
|
|
+ // Rebuild index after insertion (ordered_insert may shift elements)
|
|
+ area_index.clear();
|
|
+ for (int i = 0; i < areas.size(); i++) {
|
|
+ area_index[areas[i].area->get_self()] = i;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
_FORCE_INLINE_ void remove_area(GodotArea2D *p_area) {
|
|
- int index = areas.find(AreaCMP(p_area));
|
|
- if (index > -1) {
|
|
- areas.write[index].refCount -= 1;
|
|
- if (areas[index].refCount < 1) {
|
|
- areas.remove_at(index);
|
|
+ // FIX godot-0002: was areas.find() — O(n) linear scan, CWE-407
|
|
+ RID rid = p_area->get_self();
|
|
+ HashMap<RID, int>::Iterator it = area_index.find(rid);
|
|
+ if (it != area_index.end()) {
|
|
+ int index = it->value;
|
|
+ areas.write[index].refCount -= 1;
|
|
+ if (areas[index].refCount < 1) {
|
|
+ areas.remove_at(index);
|
|
+ area_index.clear();
|
|
+ for (int i = 0; i < areas.size(); i++) {
|
|
+ area_index[areas[i].area->get_self()] = i;
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
|
|
# Note: The index-rebuild on every insert/remove is safe because area changes
|
|
# are rare (enter/exit triggers only). The hotpath — pre_solve() calling
|
|
# add_area()/remove_area() per overlapping pair per tick — now pays O(1)
|
|
# for the find(), with O(k) index rebuild only on overlap change.
|
|
# Alternatively: drop ordered_insert entirely, use HashMap<RID, AreaCMP>
|
|
# and sort only in get_areas() / query paths. Simpler and faster.
|