70 lines
2.5 KiB
Diff
70 lines
2.5 KiB
Diff
# UNDF: UNDF-2026-000000759
|
||
# UNDF: (leave blank)
|
||
--- a/scene/3d/spring_bone_simulator_3d.cpp
|
||
+++ b/scene/3d/spring_bone_simulator_3d.cpp
|
||
@@ -1427,39 +1427,41 @@ void SpringBoneSimulator3D::_process_collisions() {
|
||
if (collisions_dirty) {
|
||
collisions_dirty = false;
|
||
}
|
||
collisions.clear();
|
||
for (int i = 0; i < get_child_count(); i++) {
|
||
SpringBoneCollision3D *c = Object::cast_to<SpringBoneCollision3D>(get_child(i));
|
||
if (c) {
|
||
collisions.push_back(c->get_instance_id());
|
||
}
|
||
}
|
||
|
||
+ // CWE-407 fix: build O(1) lookup set to replace O(N) LocalVector::has/find per
|
||
+ // setting×collision_path iteration. Original code scanned the entire `collisions`
|
||
+ // LocalVector (N items) for every entry in setting_collisions (C items) across all
|
||
+ // settings (S bones), giving O(S×C×N). With a HashSet the inner membership test
|
||
+ // drops to O(1): total cost O(N + S×C).
|
||
+ HashSet<ObjectID> collision_set;
|
||
+ // Also build index map for find() call in the deny-list path.
|
||
+ HashMap<ObjectID, int> collision_index_map;
|
||
+ for (uint32_t ci = 0; ci < collisions.size(); ci++) {
|
||
+ collision_set.insert(collisions[ci]);
|
||
+ collision_index_map[collisions[ci]] = (int)ci;
|
||
+ }
|
||
+
|
||
bool setting_updated = false;
|
||
|
||
for (int i = 0; i < settings.size(); i++) {
|
||
LocalVector<ObjectID> &cache = settings[i]->cached_collisions;
|
||
cache.clear();
|
||
if (!settings[i]->enable_all_child_collisions) {
|
||
// Allow list.
|
||
Vector<NodePath> &setting_collisions = settings[i]->collisions;
|
||
for (int j = 0; j < setting_collisions.size(); j++) {
|
||
Node *n = get_node_or_null(setting_collisions[j]);
|
||
if (!n) {
|
||
continue;
|
||
}
|
||
ObjectID id = n->get_instance_id();
|
||
- if (!collisions.has(id)) {
|
||
+ if (!collision_set.has(id)) {
|
||
setting_collisions.write[j] = NodePath(); // Clear path if not found.
|
||
} else {
|
||
cache.push_back(id);
|
||
}
|
||
}
|
||
} else {
|
||
// Deny list.
|
||
LocalVector<uint32_t> masks;
|
||
Vector<NodePath> &setting_exclude_collisions = settings[i]->exclude_collisions;
|
||
for (int j = 0; j < setting_exclude_collisions.size(); j++) {
|
||
Node *n = get_node_or_null(setting_exclude_collisions[j]);
|
||
if (!n) {
|
||
continue;
|
||
}
|
||
ObjectID id = n->get_instance_id();
|
||
- int find = collisions.find(id);
|
||
- if (find < 0) {
|
||
+ const int *find_ptr = collision_index_map.getptr(id);
|
||
+ if (!find_ptr) {
|
||
setting_exclude_collisions.write[j] = NodePath(); // Clear path if not found.
|
||
} else {
|
||
- masks.push_back((uint32_t)find);
|
||
+ masks.push_back((uint32_t)*find_ptr);
|
||
}
|
||
}
|