103 lines
5.1 KiB
Diff
103 lines
5.1 KiB
Diff
# UNDF: UNDF-2026-000000758
|
||
# UNDF: (leave blank)
|
||
--- a/scene/gui/graph_edit_arranger.cpp
|
||
+++ b/scene/gui/graph_edit_arranger.cpp
|
||
@@ -427,24 +427,33 @@ void GraphEditArranger::_calculate_inner_shifts(Dictionary &r_inner_shifts, con
|
||
float GraphEditArranger::_calculate_threshold(const StringName &p_v, const StringName &p_w, const Dictionary &r_node_names, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_inner_shift, real_t p_current_threshold, const HashMap<StringName, Vector2> &r_node_positions) {
|
||
#define MAX_ORDER 2147483647
|
||
-#define ORDER(node, layers) \
|
||
- for (unsigned int i = 0; i < layers.size(); i++) { \
|
||
- int index = layers[i].find(node); \
|
||
- if (index > 0) { \
|
||
- order = index; \
|
||
- break; \
|
||
- } \
|
||
- order = MAX_ORDER; \
|
||
- }
|
||
+// CWE-407 fix: build O(1) position lookup to replace O(N) Vector::find per connection.
|
||
+// The original ORDER macro iterated all layers × nodes-per-layer (total O(N)) for each
|
||
+// of the C connections, giving O(C×N) for _calculate_threshold. PRED had the same
|
||
+// pattern inside the do-while walk in _place_block (O(N) per walk step).
|
||
+// Fix: pass a pre-built HashMap<StringName,int> node_order that maps each node name
|
||
+// to its within-layer index. Look-up is O(1); total cost drops to O(N+C).
|
||
+#define ORDER(node, node_order_map) \
|
||
+ { \
|
||
+ const int *_op = node_order_map.getptr(node); \
|
||
+ order = _op ? *_op : MAX_ORDER; \
|
||
+ }
|
||
|
||
int order = MAX_ORDER;
|
||
float threshold = p_current_threshold;
|
||
+
|
||
+ // Build node_order: maps each node to its within-layer index.
|
||
+ // The original ORDER macro used `if (index > 0)` — position-0 nodes were treated
|
||
+ // as "not found" (returned MAX_ORDER). We preserve this: only store j >= 1.
|
||
+ // Nodes at j==0 will not be in the map, so getptr() returns nullptr → MAX_ORDER.
|
||
+ HashMap<StringName, int> node_order;
|
||
+ for (unsigned int i = 0; i < r_layers.size(); i++) {
|
||
+ for (int j = 1; j < r_layers[i].size(); j++) { // j=1: preserve original > 0 guard
|
||
+ node_order[r_layers[i][j]] = j;
|
||
+ }
|
||
+ }
|
||
+
|
||
if (p_v == p_w) {
|
||
int min_order = MAX_ORDER;
|
||
Ref<GraphEdit::Connection> incoming;
|
||
const Vector<Ref<GraphEdit::Connection>> connection_list = graph_edit->get_connections();
|
||
for (const Ref<GraphEdit::Connection> &connection : connection_list) {
|
||
if (connection->to_node == p_w) {
|
||
- ORDER(connection->from_node, r_layers);
|
||
+ ORDER(connection->from_node, node_order);
|
||
if (min_order > order) {
|
||
min_order = order;
|
||
incoming = connection;
|
||
@@ -468,7 +477,7 @@ float GraphEditArranger::_calculate_threshold(const StringName &p_v, const Stri
|
||
const Vector<Ref<GraphEdit::Connection>> connection_list = graph_edit->get_connections();
|
||
for (const Ref<GraphEdit::Connection> &connection : connection_list) {
|
||
if (connection->from_node == p_w) {
|
||
- ORDER(connection->to_node, r_layers);
|
||
+ ORDER(connection->to_node, node_order);
|
||
if (min_order > order) {
|
||
min_order = order;
|
||
outgoing = connection;
|
||
@@ -499,12 +508,20 @@ float GraphEditArranger::_calculate_threshold(const StringName &p_v, const Stri
|
||
|
||
void GraphEditArranger::_place_block(const StringName &p_v, float p_delta, const HashMap<int, Vector<StringName>> &r_layers, const Dictionary &r_root, const Dictionary &r_align, const Dictionary &r_node_name, const Dictionary &r_inner_shift, Dictionary &r_sink, Dictionary &r_shift, HashMap<StringName, Vector2> &r_node_positions) {
|
||
-#define PRED(node, layers) \
|
||
- for (unsigned int i = 0; i < layers.size(); i++) { \
|
||
- int index = layers[i].find(node); \
|
||
- if (index > 0) { \
|
||
- predecessor = layers[i][index - 1]; \
|
||
- break; \
|
||
- } \
|
||
- predecessor = StringName(); \
|
||
- }
|
||
+// CWE-407 fix: same O(N) Vector::find replaced with O(1) map look-up.
|
||
+// Build predecessor_map: node -> its predecessor (previous node in same layer).
|
||
+#define PRED(node, pred_map) \
|
||
+ { \
|
||
+ const StringName *_pp = pred_map.getptr(node); \
|
||
+ predecessor = _pp ? *_pp : StringName(); \
|
||
+ }
|
||
+
|
||
+ // Build predecessor_map once: maps each node (except first in its layer) to
|
||
+ // the node immediately before it in the same layer.
|
||
+ HashMap<StringName, StringName> predecessor_map;
|
||
+ for (unsigned int i = 0; i < r_layers.size(); i++) {
|
||
+ for (int j = 1; j < r_layers[i].size(); j++) {
|
||
+ predecessor_map[r_layers[i][j]] = r_layers[i][j - 1];
|
||
+ }
|
||
+ }
|
||
|
||
StringName predecessor;
|
||
StringName successor;
|
||
@@ -514,7 +531,7 @@ void GraphEditArranger::_place_block(const StringName &p_v, float p_delta, cons
|
||
if (pos.y == FLT_MAX) {
|
||
pos.y = 0;
|
||
bool initial = false;
|
||
StringName w = p_v;
|
||
real_t threshold = FLT_MIN;
|
||
do {
|
||
- PRED(w, r_layers);
|
||
+ PRED(w, predecessor_map);
|
||
if (predecessor != StringName()) {
|