java-topology/defects/mongodb/patch/0001.patch
russell@unturf.com 9934133dcf whitepaper: 312 sites / 151 ecosystems — wave2+3 defect tables and PDF rebuild
Add 88 new defect entries to HIGH and MEDIUM tables:
  HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
        vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
        tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
        allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
        mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
        linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
        perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002

  MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
          cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
          pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
          ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
          r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
          ovs-0001, onos-0003, odl-0002, jetty-0001

PDF: 976K
2026-03-27 15:23:43 -04:00

140 lines
5.9 KiB
Diff

diff --git a/src/mongo/db/query/index_tag.h b/src/mongo/db/query/index_tag.h
index 7465ab84..db15bf62 100644
--- a/src/mongo/db/query/index_tag.h
+++ b/src/mongo/db/query/index_tag.h
@@ -40,6 +40,7 @@
#include <deque>
#include <memory>
#include <string>
+#include <unordered_set>
#include <utility>
#include <vector>
@@ -103,8 +104,11 @@ class RelevantTag final : public MatchExpression::TagData {
public:
RelevantTag() : elemMatchExpr(nullptr), pathPrefix("") {}
- std::vector<size_t> first;
- std::vector<size_t> notFirst;
+ // CWE-407 fix: changed from std::vector<size_t> to std::unordered_set<size_t> so that
+ // membership tests in isIndexAssigned() and stripInvalidAssignments*() are O(1) instead of
+ // O(n), eliminating the O(P*I) quadratic scan in the index selection strip passes.
+ std::unordered_set<size_t> first;
+ std::unordered_set<size_t> notFirst;
// We don't know the full path from a node unless we keep notes as we traverse from the
// root. We do this once and store it.
@@ -133,12 +137,12 @@ public:
void debugString(StringBuilder* builder) const override {
*builder << " || First: ";
- for (size_t i = 0; i < first.size(); ++i) {
- *builder << first[i] << " ";
+ for (size_t idx : first) {
+ *builder << idx << " ";
}
*builder << "notFirst: ";
- for (size_t i = 0; i < notFirst.size(); ++i) {
- *builder << notFirst[i] << " ";
+ for (size_t idx : notFirst) {
+ *builder << idx << " ";
}
*builder << "full path: " << path << "\n";
}
diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp
index 90392cbe..39904213 100644
--- a/src/mongo/db/query/planner_ixselect.cpp
+++ b/src/mongo/db/query/planner_ixselect.cpp
@@ -816,9 +816,9 @@ void QueryPlannerIXSelect::rateIndices(MatchExpression* node,
queryContext,
nodeIsNotChild)) {
if (keyPatternIndex == 0) {
- rt->first.push_back(i);
+ rt->first.insert(i);
} else {
- rt->notFirst.push_back(i);
+ rt->notFirst.insert(i);
}
}
++keyPatternIndex;
@@ -937,17 +937,14 @@ void QueryPlannerIXSelect::stripUnneededAssignments(MatchExpression* node,
// Look through all of the indices for which this predicate can be answered with
// the leading field of the index.
- for (std::vector<size_t>::const_iterator i = rt->first.begin(); i != rt->first.end();
- ++i) {
- size_t index = *i;
-
+ for (size_t index : rt->first) {
if (indices[index].unique && 1 == indices[index].keyPattern.nFields()) {
// Found an EQ predicate which can use a single-field unique index.
// Clear assignments from the entire tree, and add back a single assignment
// for 'child' to the unique index.
clearAssignments(node);
RelevantTag* newRt = indexTagCast<RelevantTag>(child->getTag());
- newRt->first.push_back(index);
+ newRt->first.insert(index);
// Tag state has been reset in the entire subtree at 'root'; nothing
// else for us to do.
@@ -975,16 +972,9 @@ static void removeIndexRelevantTag(MatchExpression* node, size_t idx) {
return;
}
- vector<size_t>::iterator firstIt = std::find(tag->first.begin(), tag->first.end(), idx);
- if (firstIt != tag->first.end()) {
- tag->first.erase(firstIt);
- }
-
- vector<size_t>::iterator notFirstIt =
- std::find(tag->notFirst.begin(), tag->notFirst.end(), idx);
- if (notFirstIt != tag->notFirst.end()) {
- tag->notFirst.erase(notFirstIt);
- }
+ // CWE-407 fix: unordered_set::erase(value) is O(1); replaces O(n) std::find + erase.
+ tag->first.erase(idx);
+ tag->notFirst.erase(idx);
}
namespace {
@@ -1081,10 +1071,8 @@ bool isIndexAssigned(RelevantTag* tag, size_t idx) {
return false;
}
- bool inFirst = tag->first.end() != std::find(tag->first.begin(), tag->first.end(), idx);
- bool inNotFirst =
- tag->notFirst.end() != std::find(tag->notFirst.begin(), tag->notFirst.end(), idx);
- return inFirst || inNotFirst;
+ // CWE-407 fix: O(1) set lookup replaces O(n) std::find on vector.
+ return tag->first.count(idx) || tag->notFirst.count(idx);
}
// Returns true for $and and $elemMatch as they consist of a set of predicates that are suitable for
@@ -1307,10 +1295,9 @@ static void stripInvalidAssignmentsToTextIndex(MatchExpression* node,
continue;
}
- bool inFirst = tag->first.end() != std::find(tag->first.begin(), tag->first.end(), idx);
-
- bool inNotFirst =
- tag->notFirst.end() != std::find(tag->notFirst.begin(), tag->notFirst.end(), idx);
+ // CWE-407 fix: O(1) set lookup replaces O(n) std::find.
+ bool inFirst = tag->first.count(idx) != 0;
+ bool inNotFirst = tag->notFirst.count(idx) != 0;
if (inFirst || inNotFirst) {
// Great! 'child' was assigned to our index.
@@ -1421,10 +1408,9 @@ static void stripInvalidAssignmentsTo2dsphereIndex(MatchExpression* node, size_t
continue;
}
- bool inFirst = tag->first.end() != std::find(tag->first.begin(), tag->first.end(), idx);
-
- bool inNotFirst =
- tag->notFirst.end() != std::find(tag->notFirst.begin(), tag->notFirst.end(), idx);
+ // CWE-407 fix: O(1) set lookup replaces O(n) std::find.
+ bool inFirst = tag->first.count(idx) != 0;
+ bool inNotFirst = tag->notFirst.count(idx) != 0;
// If there is an index assignment...
if (inFirst || inNotFirst) {