41 lines
1.4 KiB
Diff
41 lines
1.4 KiB
Diff
# UNDF: UNDF-2026-000000083
|
|
--- a/scene/main/scene_tree.h
|
|
+++ b/scene/main/scene_tree.h
|
|
@@ -117,6 +117,7 @@ class SceneTree : public MainLoop {
|
|
|
|
struct Group {
|
|
Vector<Node *> nodes;
|
|
+ HashSet<Node *> node_set; // O(1) membership — shadow index for Vector
|
|
bool changed = false;
|
|
};
|
|
|
|
--- a/scene/main/scene_tree.cpp
|
|
+++ b/scene/main/scene_tree.cpp
|
|
@@ -171,14 +171,16 @@ SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_node) {
|
|
if (!E) {
|
|
E = group_map.insert(p_group, Group());
|
|
}
|
|
|
|
- ERR_FAIL_COND_V_MSG(E->value.nodes.has(p_node), &E->value, "Already in group: " + p_group + ".");
|
|
+ // FIX godot-0001: was nodes.has(p_node) — O(n) linear scan, CWE-407
|
|
+ // nodes.has() uses Vector linear scan: O(n) per add_to_group call.
|
|
+ // node_set provides O(1) lookup. Vector preserved for ordered iteration.
|
|
+ ERR_FAIL_COND_V_MSG(E->value.node_set.has(p_node), &E->value, "Already in group: " + p_group + ".");
|
|
E->value.nodes.push_back(p_node);
|
|
+ E->value.node_set.insert(p_node);
|
|
E->value.changed = true;
|
|
return &E->value;
|
|
}
|
|
|
|
void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) {
|
|
_THREAD_SAFE_METHOD_
|
|
|
|
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
|
|
ERR_FAIL_COND(!E);
|
|
|
|
E->value.nodes.erase(p_node);
|
|
+ E->value.node_set.erase(p_node);
|
|
if (E->value.nodes.is_empty()) {
|
|
group_map.remove(E);
|
|
}
|
|
}
|