# UNDF: UNDF-2026-000000778 # UNDF: (leave blank) # CWE-407: node_runtime.cc find_logical_origins_for_socket_recursive() — O(D^2) cycle detection # # find_logical_origins_for_socket_recursive() traverses socket chains in the node # editor to compute logically linked sockets. It uses a Vector # called sockets_in_current_chain and calls .contains() on it to detect cycles # (reroute loops). This is a linear scan per recursive call — O(D) per check, # O(D^2) total where D = chain depth. # # Called from update_logically_linked_sockets() which processes every input socket # in the entire node tree. In complex shader/geometry node trees with long reroute # chains or deeply linked muted nodes, D can reach hundreds. # # Fix: maintain a parallel Set for O(1) cycle detection. # Keep the Vector for ordered pop_last() tracking. # # Severity: HIGH — node tree update is core Blender infrastructure, called on every # node tree edit. Overhead: ~250x at D=500 chain depth. # --- a/source/blender/blenkernel/intern/node_runtime.cc +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -156,12 +156,14 @@ static void find_logical_origins_for_socket_recursive( bNodeSocket &input_socket, bool only_follow_first_input_link, Vector &sockets_in_current_chain, + Set &sockets_in_current_chain_set, Vector &r_logical_origins, Vector &r_skipped_origins) { - if (sockets_in_current_chain.contains(&input_socket)) { + if (sockets_in_current_chain_set.contains(&input_socket)) { /* Protect against reroute recursions. */ return; } sockets_in_current_chain.append(&input_socket); + sockets_in_current_chain_set.add(&input_socket); Span links_to_check = input_socket.runtime->directly_linked_links; @@ -207,6 +209,7 @@ sockets_in_current_chain.pop_last(); + sockets_in_current_chain_set.remove(&input_socket); }