# UNDF: UNDF-2026-000000056 diff --git a/src/include/duckdb/planner/binder.hpp b/src/include/duckdb/planner/binder.hpp index 31e7489..7b31df0 100644 --- a/src/include/duckdb/planner/binder.hpp +++ b/src/include/duckdb/planner/binder.hpp @@ -28,6 +28,7 @@ #include "duckdb/planner/bound_constraint.hpp" #include "duckdb/planner/logical_operator.hpp" #include "duckdb/common/enums/copy_option_mode.hpp" +#include "duckdb/planner/column_binding_map.hpp" //! fwd declare namespace duckdb_re2 { @@ -111,14 +112,21 @@ public: void AddColumn(container_type::value_type info) { // Add to beginning + correlated_binding_set.insert(info.binding); correlated_columns.insert(correlated_columns.begin(), std::move(info)); delim_index++; } void AddColumnToBack(container_type::value_type info) { // Add to end + correlated_binding_set.insert(info.binding); correlated_columns.push_back(std::move(info)); } + //! CWE-407 fix: O(1) membership test replaces O(n) std::find over vector. + bool contains(const CorrelatedColumnInfo &info) const { // NOLINT: match stl case + return correlated_binding_set.count(info.binding) != 0; + } + void SetDelimIndexToZero() { delim_index = 0; } @@ -141,6 +149,7 @@ public: void clear() { // NOLINT: match stl case correlated_columns.clear(); + correlated_binding_set.clear(); } container_type::iterator begin() { // NOLINT: match stl case @@ -161,6 +170,8 @@ public: private: container_type correlated_columns; + //! CWE-407 fix: shadow set for O(1) membership tests in AddCorrelatedColumn / ExtractCorrelatedColumns. + column_binding_set_t correlated_binding_set; idx_t delim_index; }; diff --git a/src/planner/binder.cpp b/src/planner/binder.cpp index bfbfdcb..bbd6fce 100644 --- a/src/planner/binder.cpp +++ b/src/planner/binder.cpp @@ -283,8 +283,8 @@ void Binder::MergeCorrelatedColumns(CorrelatedColumns &other) { } void Binder::AddCorrelatedColumn(const CorrelatedColumnInfo &info) { - // we only add correlated columns to the list if they are not already there - if (std::find(correlated_columns.begin(), correlated_columns.end(), info) == correlated_columns.end()) { + // CWE-407 fix: O(1) set membership check replaces O(n) std::find on vector. + if (!correlated_columns.contains(info)) { correlated_columns.AddColumn(info); } } diff --git a/src/planner/expression_binder/lateral_binder.cpp b/src/planner/expression_binder/lateral_binder.cpp index e52eced..da3d623 100644 --- a/src/planner/expression_binder/lateral_binder.cpp +++ b/src/planner/expression_binder/lateral_binder.cpp @@ -16,7 +16,8 @@ void LateralBinder::ExtractCorrelatedColumns(Expression &expr) { if (bound_colref.depth > 0) { // add the correlated column info CorrelatedColumnInfo info(bound_colref); - if (std::find(correlated_columns.begin(), correlated_columns.end(), info) == correlated_columns.end()) { + // CWE-407 fix: O(1) set membership check replaces O(n) std::find on vector. + if (!correlated_columns.contains(info)) { correlated_columns.AddColumn(std::move(info)); // TODO is adding to the front OK here? } }