java-topology/defects/godot/patch/godot-0001-scene-tree-group-hashset.patch

40 lines
1.3 KiB
Diff

--- 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);
}
}