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
140 lines
5.9 KiB
Diff
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) {
|