diff options
author | Lynne Wang <lynne.wang@mongodb.com> | 2022-07-03 21:09:25 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-07-03 22:45:24 +0000 |
commit | 44d8e4b0819c89ae5be8fee4d10a525595158220 (patch) | |
tree | 03aae10a1429267bf5fc20859f8fcbcf50ce2e51 /src/mongo/db/matcher | |
parent | da79de3da49f2337ec1dca076b2ac85eb246e2c0 (diff) | |
download | mongo-44d8e4b0819c89ae5be8fee4d10a525595158220.tar.gz |
SERVER-64002 Consistently disallow out-of-bounds access to the children vector of MatchExpressions
Diffstat (limited to 'src/mongo/db/matcher')
33 files changed, 318 insertions, 34 deletions
diff --git a/src/mongo/db/matcher/expression_always_boolean.h b/src/mongo/db/matcher/expression_always_boolean.h index 6e0e2cdfbc8..6a97367aff5 100644 --- a/src/mongo/db/matcher/expression_always_boolean.h +++ b/src/mongo/db/matcher/expression_always_boolean.h @@ -79,7 +79,7 @@ public: } MatchExpression* getChild(size_t i) const override { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400202); } void resetChild(size_t, MatchExpression*) override { diff --git a/src/mongo/db/matcher/expression_always_boolean_test.cpp b/src/mongo/db/matcher/expression_always_boolean_test.cpp index e18c7be11e8..3290f5079a0 100644 --- a/src/mongo/db/matcher/expression_always_boolean_test.cpp +++ b/src/mongo/db/matcher/expression_always_boolean_test.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" #include "mongo/db/matcher/expression_always_boolean.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -73,5 +74,23 @@ TEST(AlwaysTrueMatchExpression, EquivalentReturnsCorrectResults) { ASSERT_FALSE(trueExpr->equivalent(&falseExpr)); } +DEATH_TEST_REGEX(AlwaysTrueMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400202") { + auto trueExpr = std::make_unique<AlwaysTrueMatchExpression>(); + + ASSERT_EQ(trueExpr->numChildren(), 0); + ASSERT_THROWS_CODE(trueExpr->getChild(0), AssertionException, 6400202); +} + +DEATH_TEST_REGEX(AlwaysFalseMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400202") { + auto falseExpr = std::make_unique<AlwaysFalseMatchExpression>(); + + ASSERT_EQ(falseExpr->numChildren(), 0); + ASSERT_THROWS_CODE(falseExpr->getChild(0), AssertionException, 6400202); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/expression_arity.h b/src/mongo/db/matcher/expression_arity.h index 90286200e21..a16dcf346a2 100644 --- a/src/mongo/db/matcher/expression_arity.h +++ b/src/mongo/db/matcher/expression_arity.h @@ -90,7 +90,7 @@ public: } MatchExpression* getChild(size_t i) const final { - invariant(i < nargs); + tassert(6400203, "Out-of-bounds access to child of MatchExpression.", i < nargs); return _expressions[i].get(); } diff --git a/src/mongo/db/matcher/expression_array.h b/src/mongo/db/matcher/expression_array.h index 1b6cb5dfcc9..b1d82248c1b 100644 --- a/src/mongo/db/matcher/expression_array.h +++ b/src/mongo/db/matcher/expression_array.h @@ -101,6 +101,7 @@ public: } virtual MatchExpression* getChild(size_t i) const { + tassert(6400204, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); return _sub.get(); } @@ -168,6 +169,7 @@ public: } virtual MatchExpression* getChild(size_t i) const { + tassert(6400205, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); return _subs[i].get(); } @@ -215,6 +217,7 @@ public: } MatchExpression* getChild(size_t i) const override { + tassert(6400206, "SizeMatchExpression does not have any children.", i < numChildren()); return nullptr; } diff --git a/src/mongo/db/matcher/expression_array_test.cpp b/src/mongo/db/matcher/expression_array_test.cpp index e1dea305466..7d9cbd6ef93 100644 --- a/src/mongo/db/matcher/expression_array_test.cpp +++ b/src/mongo/db/matcher/expression_array_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_tree.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -153,6 +154,18 @@ TEST(ElemMatchObjectMatchExpression, Collation) { ASSERT(op.matchesSingleElement(notMatch["a"])); } +DEATH_TEST_REGEX(ElemMatchObjectMatchExpression, + GetChildFailsIndexGreaterThanOne, + "Tripwire assertion.*6400204") { + auto baseOperand = BSON("c" << 6); + auto eq = std::make_unique<EqualityMatchExpression>("c", baseOperand["c"]); + auto op = ElemMatchObjectMatchExpression{"a.b", std::move(eq)}; + + const size_t numChildren = 1; + ASSERT_EQ(op.numChildren(), numChildren); + ASSERT_THROWS_CODE(op.getChild(numChildren), AssertionException, 6400204); +} + /** TEST(ElemMatchObjectMatchExpression, MatchesIndexKey) { auto baseOperand = BSON("b" << 5); @@ -245,6 +258,18 @@ TEST(ElemMatchValueMatchExpression, ElemMatchKey) { ASSERT_EQUALS("2", details.elemMatchKey()); } +DEATH_TEST_REGEX(ElemMatchValueMatchExpression, + GetChildFailsOnIndexLargerThanChildSet, + "Tripwire assertion.*6400205") { + auto baseOperand = BSON("$gt" << 6); + auto gt = std::make_unique<GTMatchExpression>("", baseOperand["$gt"]); + auto op = ElemMatchValueMatchExpression{"a.b", std::unique_ptr<MatchExpression>{std::move(gt)}}; + + const size_t numChildren = 1; + ASSERT_EQ(op.numChildren(), numChildren); + ASSERT_THROWS_CODE(op.getChild(numChildren), AssertionException, 6400205); +} + /** TEST(ElemMatchValueMatchExpression, MatchesIndexKey) { auto baseOperand = BSON("$lt" << 5); @@ -410,6 +435,16 @@ TEST(SizeMatchExpression, Equivalent) { ASSERT(!e1.equivalent(&e3)); } +DEATH_TEST_REGEX(SizeMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400206") { + auto e1 = SizeMatchExpression{"a", 5}; + + const size_t numChildren = 0; + ASSERT_EQ(e1.numChildren(), numChildren); + ASSERT_THROWS_CODE(e1.getChild(0), AssertionException, 6400206); +} + /** TEST(SizeMatchExpression, MatchesIndexKey) { auto operand = BSON("$size" << 4); diff --git a/src/mongo/db/matcher/expression_expr.h b/src/mongo/db/matcher/expression_expr.h index 281fdd3afd6..0d1110f5bac 100644 --- a/src/mongo/db/matcher/expression_expr.h +++ b/src/mongo/db/matcher/expression_expr.h @@ -88,7 +88,7 @@ public: } MatchExpression* getChild(size_t i) const final { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400207); } void resetChild(size_t, MatchExpression*) { diff --git a/src/mongo/db/matcher/expression_expr_test.cpp b/src/mongo/db/matcher/expression_expr_test.cpp index 5ff0cbf88e9..801b3634813 100644 --- a/src/mongo/db/matcher/expression_expr_test.cpp +++ b/src/mongo/db/matcher/expression_expr_test.cpp @@ -37,6 +37,7 @@ #include "mongo/db/matcher/matcher.h" #include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -735,5 +736,16 @@ TEST_F(ExprMatchTest, ExpressionEvaluationReturnsResultsCorrectly) { ASSERT_EQUALS(-2, expressionResult.coerceToInt()); } +DEATH_TEST_REGEX(ExprMatchTest, GetChildFailsIndexGreaterThanZero, "Tripwire assertion.*6400207") { + BSONObj exprBson = fromjson("{$expr: {$and: [{$eq: ['$a', 1]}, {$eq: ['$b', 2]}]}}"); + + boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); + auto matchExpr = + std::make_unique<ExprMatchExpression>(exprBson.firstElement(), std::move(expCtx)); + + ASSERT_EQ(matchExpr->numChildren(), 0); + ASSERT_THROWS_CODE(matchExpr->getChild(0), AssertionException, 6400207); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/expression_internal_bucket_geo_within.h b/src/mongo/db/matcher/expression_internal_bucket_geo_within.h index 34ec2ad9211..2395cf97c16 100644 --- a/src/mongo/db/matcher/expression_internal_bucket_geo_within.h +++ b/src/mongo/db/matcher/expression_internal_bucket_geo_within.h @@ -107,7 +107,7 @@ public: } MatchExpression* getChild(size_t i) const final { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400208); } void resetChild(size_t, MatchExpression*) { diff --git a/src/mongo/db/matcher/expression_leaf.h b/src/mongo/db/matcher/expression_leaf.h index 14fceae1f5f..bd6bc577672 100644 --- a/src/mongo/db/matcher/expression_leaf.h +++ b/src/mongo/db/matcher/expression_leaf.h @@ -101,7 +101,7 @@ public: } MatchExpression* getChild(size_t i) const override { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400209); } diff --git a/src/mongo/db/matcher/expression_leaf_test.cpp b/src/mongo/db/matcher/expression_leaf_test.cpp index 99bedfa067f..450e71d0367 100644 --- a/src/mongo/db/matcher/expression_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_leaf_test.cpp @@ -2198,4 +2198,66 @@ TEST(MatchesBSONElement, ArrayEquality) { ASSERT_FALSE(filter.matchesBSON(iObjArr)); } +DEATH_TEST_REGEX(RegexMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400209") { + BSONObj match = BSON("a" + << "b"); + BSONObj notMatch = BSON("a" + << "c"); + RegexMatchExpression regex("", "b", ""); + + ASSERT_EQ(regex.numChildren(), 0); + ASSERT_THROWS_CODE(regex.getChild(0), AssertionException, 6400209); +} + +DEATH_TEST_REGEX(ModMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400209") { + ModMatchExpression mod("a", 5, 2); + + ASSERT_EQ(mod.numChildren(), 0); + ASSERT_THROWS_CODE(mod.getChild(0), AssertionException, 6400209); +} + +DEATH_TEST_REGEX(ExistsMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400209") { + ExistsMatchExpression exists("a"); + + ASSERT_EQ(exists.numChildren(), 0); + ASSERT_THROWS_CODE(exists.getChild(0), AssertionException, 6400209); +} + +DEATH_TEST_REGEX(InMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400209") { + InMatchExpression in("a"); + + ASSERT_EQ(in.numChildren(), 0); + ASSERT_THROWS_CODE(in.getChild(0), AssertionException, 6400209); +} + +DEATH_TEST_REGEX(BitTestMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400209") { + long long bitMask = 54; + + BitsAllSetMatchExpression balls("a", bitMask); + + ASSERT_EQ(balls.numChildren(), 0); + ASSERT_THROWS_CODE(balls.getChild(0), AssertionException, 6400209); +} + +DEATH_TEST_REGEX(ComparisonMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400209") { + BSONObj operand = BSON("a" + << "string"); + EqualityMatchExpression eq("a", operand["a"]); + + ASSERT_EQ(eq.numChildren(), 0); + ASSERT_THROWS_CODE(eq.getChild(0), AssertionException, 6400209); +} + } // namespace mongo diff --git a/src/mongo/db/matcher/expression_tree.h b/src/mongo/db/matcher/expression_tree.h index f8b9179c003..f5ab4bb5a8e 100644 --- a/src/mongo/db/matcher/expression_tree.h +++ b/src/mongo/db/matcher/expression_tree.h @@ -61,6 +61,7 @@ public: } MatchExpression* getChild(size_t i) const final { + tassert(6400201, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); return _expressions[i].get(); } @@ -238,6 +239,7 @@ public: class NotMatchExpression final : public MatchExpression { public: + static constexpr int kNumChildren = 1; explicit NotMatchExpression(MatchExpression* e, clonable_ptr<ErrorAnnotation> annotation = nullptr) : MatchExpression(NOT, std::move(annotation)), _exp(e) {} @@ -270,10 +272,11 @@ public: bool equivalent(const MatchExpression* other) const final; size_t numChildren() const final { - return 1; + return kNumChildren; } MatchExpression* getChild(size_t i) const final { + tassert(6400210, "Out-of-bounds access to child of MatchExpression.", i < kNumChildren); return _exp.get(); } diff --git a/src/mongo/db/matcher/expression_tree_test.cpp b/src/mongo/db/matcher/expression_tree_test.cpp index 16c03b31336..562f6aad673 100644 --- a/src/mongo/db/matcher/expression_tree_test.cpp +++ b/src/mongo/db/matcher/expression_tree_test.cpp @@ -37,6 +37,7 @@ #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_tree.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/unittest/death_test.h" namespace mongo { @@ -85,6 +86,17 @@ TEST(NotMatchExpression, SetCollatorPropagatesToChild) { nullptr)); } +DEATH_TEST_REGEX(NotMatchExpression, + GetChildFailsIndexLargerThanOne, + "Tripwire assertion.*6400210") { + auto baseOperand = BSON("$lt" << 5); + auto lt = std::make_unique<LTMatchExpression>("a", baseOperand["$lt"]); + auto notOp = NotMatchExpression{lt.release()}; + + ASSERT_EQ(notOp.numChildren(), 1); + ASSERT_THROWS_CODE(notOp.getChild(1), AssertionException, 6400210); +} + TEST(AndOp, NoClauses) { auto andMatchExpression = AndMatchExpression{}; ASSERT(andMatchExpression.matchesBSON(BSONObj{}, nullptr)); @@ -177,6 +189,25 @@ TEST(AndOp, ElemMatchKey) { ASSERT_EQUALS("1", details.elemMatchKey()); } +DEATH_TEST_REGEX(AndOp, GetChildFailsOnIndexLargerThanChildren, "Tripwire assertion.*6400201") { + auto baseOperand1 = BSON("$gt" << 1); + auto baseOperand2 = BSON("$lt" << 10); + auto baseOperand3 = BSON("$lt" << 100); + + auto sub1 = std::make_unique<GTMatchExpression>("a", baseOperand1["$gt"]); + auto sub2 = std::make_unique<LTMatchExpression>("a", baseOperand2["$lt"]); + auto sub3 = std::make_unique<LTMatchExpression>("b", baseOperand3["$lt"]); + + auto andOp = AndMatchExpression{}; + andOp.add(std::move(sub1)); + andOp.add(std::move(sub2)); + andOp.add(std::move(sub3)); + + const size_t numChildren = 3; + ASSERT_EQ(andOp.numChildren(), numChildren); + ASSERT_THROWS_CODE(andOp.getChild(numChildren), AssertionException, 6400201); +} + TEST(OrOp, NoClauses) { auto orOp = OrMatchExpression{}; ASSERT(!orOp.matchesBSON(BSONObj{}, nullptr)); @@ -270,6 +301,24 @@ TEST(OrOp, ElemMatchKey) { ASSERT(!details.hasElemMatchKey()); } +DEATH_TEST_REGEX(OrOp, GetChildFailsOnIndexLargerThanChildren, "Tripwire assertion.*6400201") { + auto baseOperand1 = BSON("$gt" << 10); + auto baseOperand2 = BSON("$lt" << 0); + auto baseOperand3 = BSON("b" << 100); + auto sub1 = std::make_unique<GTMatchExpression>("a", baseOperand1["$gt"]); + auto sub2 = std::make_unique<LTMatchExpression>("a", baseOperand2["$lt"]); + auto sub3 = std::make_unique<EqualityMatchExpression>("b", baseOperand3["b"]); + + auto orOp = OrMatchExpression{}; + orOp.add(std::move(sub1)); + orOp.add(std::move(sub2)); + orOp.add(std::move(sub3)); + + const size_t numChildren = 3; + ASSERT_EQ(orOp.numChildren(), numChildren); + ASSERT_THROWS_CODE(orOp.getChild(numChildren), AssertionException, 6400201); +} + TEST(NorOp, NoClauses) { auto norOp = NorMatchExpression{}; ASSERT(norOp.matchesBSON(BSONObj{}, nullptr)); @@ -350,4 +399,24 @@ TEST(NorOp, Equivalent) { ASSERT(e1.equivalent(&e1)); ASSERT(!e1.equivalent(&e2)); } + +DEATH_TEST_REGEX(NorOp, GetChildFailsOnIndexLargerThanChildren, "Tripwire assertion.*6400201") { + auto baseOperand1 = BSON("$gt" << 10); + auto baseOperand2 = BSON("$lt" << 0); + auto baseOperand3 = BSON("b" << 100); + + auto sub1 = std::make_unique<GTMatchExpression>("a", baseOperand1["$gt"]); + auto sub2 = std::make_unique<LTMatchExpression>("a", baseOperand2["$lt"]); + auto sub3 = std::make_unique<EqualityMatchExpression>("b", baseOperand3["b"]); + + auto norOp = NorMatchExpression{}; + norOp.add(std::move(sub1)); + norOp.add(std::move(sub2)); + norOp.add(std::move(sub3)); + + const size_t numChildren = 3; + ASSERT_EQ(norOp.numChildren(), numChildren); + ASSERT_THROWS_CODE(norOp.getChild(numChildren), AssertionException, 6400201); +} + } // namespace mongo diff --git a/src/mongo/db/matcher/expression_where_base.h b/src/mongo/db/matcher/expression_where_base.h index 550e94d1d37..3f5099d7180 100644 --- a/src/mongo/db/matcher/expression_where_base.h +++ b/src/mongo/db/matcher/expression_where_base.h @@ -51,7 +51,7 @@ public: } MatchExpression* getChild(size_t i) const final { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400211); } void resetChild(size_t, MatchExpression*) { diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index.h b/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index.h index 0a613b23303..8d830f916b9 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index.h @@ -45,6 +45,7 @@ class InternalSchemaAllElemMatchFromIndexMatchExpression final : public ArrayMatchingMatchExpression { public: static constexpr StringData kName = "$_internalSchemaAllElemMatchFromIndex"_sd; + static constexpr int kNumChildren = 1; InternalSchemaAllElemMatchFromIndexMatchExpression( StringData path, @@ -93,16 +94,16 @@ public: } size_t numChildren() const final { - return 1; + return kNumChildren; } MatchExpression* getChild(size_t i) const final { - invariant(i == 0); + tassert(6400200, "Out-of-bounds access to child of MatchExpression.", i < kNumChildren); return _expression->getFilter(); } void resetChild(size_t i, MatchExpression* other) { - tassert(6329407, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); + tassert(6329407, "Out-of-bounds access to child of MatchExpression.", i < kNumChildren); _expression->resetFilter(other); }; diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index_test.cpp index 49e1b3b0235..dd1be3e030f 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_all_elem_match_from_index_test.cpp @@ -127,13 +127,14 @@ TEST(InternalSchemaAllElemMatchFromIndexMatchExpression, FindsFirstMismatchInArr DEATH_TEST_REGEX(InternalSchemaAllElemMatchFromIndexMatchExpression, GetChildFailsIndexGreaterThanOne, - "Invariant failure.*i == 0") { + "Tripwire assertion.*6400200") { auto query = fromjson("{'a.b': {$_internalSchemaAllElemMatchFromIndex: [2, {a: {$lt: 5}}]}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); - objMatch.getValue()->getChild(1); + ASSERT_EQ(objMatch.getValue()->numChildren(), 1); + ASSERT_THROWS_CODE(objMatch.getValue()->getChild(1), AssertionException, 6400200); } } // namespace diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties.h b/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties.h index 08e1a1affc6..a55c268bee7 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties.h @@ -149,7 +149,7 @@ public: } MatchExpression* getChild(size_t i) const final { - invariant(i < numChildren()); + tassert(6400212, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); if (i == 0) { return _otherwise->getFilter(); diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties_test.cpp index 399d8917001..b14a1b8adca 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_allowed_properties_test.cpp @@ -135,9 +135,9 @@ TEST(InternalSchemaAllowedPropertiesMatchExpression, HasCorrectNumberOfChilden) ASSERT(objMatch.getValue()->getChild(0)); } -DEATH_TEST(InternalSchemaAllowedPropertiesMatchExpression, - GetChildFailsOnIndexLargerThanChildSet, - "i < numChildren()") { +DEATH_TEST_REGEX(InternalSchemaAllowedPropertiesMatchExpression, + GetChildFailsOnIndexLargerThanChildSet, + "Tripwire assertion.*6400212") { auto query = fromjson( "{$_internalSchemaAllowedProperties: {properties: ['a'], namePlaceholder: 'i'," "patternProperties: [{regex: /a/, expression: {i: 1}}], otherwise: {i: 7}}}"); @@ -146,6 +146,7 @@ DEATH_TEST(InternalSchemaAllowedPropertiesMatchExpression, ASSERT_OK(objMatch.getStatus()); const size_t numChildren = 2; - objMatch.getValue()->getChild(numChildren); + ASSERT_EQ(objMatch.getValue()->numChildren(), numChildren); + ASSERT_THROWS_CODE(objMatch.getValue()->getChild(numChildren), AssertionException, 6400212); } } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_eq.h b/src/mongo/db/matcher/schema/expression_internal_schema_eq.h index 3f604294f60..30882ca6c21 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_eq.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_eq.h @@ -68,7 +68,7 @@ public: } MatchExpression* getChild(size_t i) const final { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400213); } void resetChild(size_t, MatchExpression*) override { diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_eq_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_eq_test.cpp index 8be245c1fbc..25cacca243e 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_eq_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_eq_test.cpp @@ -33,6 +33,7 @@ #include "mongo/db/matcher/matcher.h" #include "mongo/db/matcher/schema/expression_internal_schema_eq.h" #include "mongo/db/pipeline/expression_context_for_test.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -137,5 +138,16 @@ TEST(InternalSchemaEqMatchExpression, EquivalentToClone) { auto clone = rootDocEq.getMatchExpression()->shallowClone(); ASSERT_TRUE(rootDocEq.getMatchExpression()->equivalent(clone.get())); } + +DEATH_TEST_REGEX(InternalSchemaEqMatchExpression, + GetChildFailsLargerThanZero, + "Tripwire assertion.*6400213") { + BSONObj operand = BSON("a" << 5); + InternalSchemaEqMatchExpression eq("a", operand["a"]); + + ASSERT_EQ(eq.numChildren(), 0); + ASSERT_THROWS_CODE(eq.getChild(0), AssertionException, 6400213); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index.h b/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index.h index 8fff1225bf3..3f30356b6aa 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index.h @@ -43,6 +43,7 @@ namespace mongo { class InternalSchemaMatchArrayIndexMatchExpression final : public ArrayMatchingMatchExpression { public: static constexpr StringData kName = "$_internalSchemaMatchArrayIndex"_sd; + static constexpr int kNumChildren = 1; InternalSchemaMatchArrayIndexMatchExpression( StringData path, @@ -82,16 +83,16 @@ public: } size_t numChildren() const final { - return 1; + return kNumChildren; } MatchExpression* getChild(size_t i) const final { - invariant(i == 0); + tassert(6400214, "Out-of-bounds access to child of MatchExpression.", i < kNumChildren); return _expression->getFilter(); } void resetChild(size_t i, MatchExpression* other) final override { - tassert(6329409, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); + tassert(6329409, "Out-of-bounds access to child of MatchExpression.", i < kNumChildren); _expression->resetFilter(other); } diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index_test.cpp index 854c2cf73a8..b6308f7ca0a 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_match_array_index_test.cpp @@ -129,8 +129,8 @@ TEST(InternalSchemaMatchArrayIndexMatchExpression, HasSingleChild) { } DEATH_TEST_REGEX(InternalSchemaMatchArrayIndexMatchExpression, - GetChildFailsIndexGreaterThanZero, - "Invariant failure.*i == 0") { + GetChildFailsIndexGreaterThanOne, + "Tripwire assertion.*6400214") { auto query = fromjson( "{foo: {$_internalSchemaMatchArrayIndex:" "{index: 0, namePlaceholder: 'i', expression: {i: {$type: 'number'}}}}}"); @@ -138,7 +138,8 @@ DEATH_TEST_REGEX(InternalSchemaMatchArrayIndexMatchExpression, auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); - objMatch.getValue()->getChild(1); + ASSERT_EQ(objMatch.getValue()->numChildren(), 1); + ASSERT_THROWS_CODE(objMatch.getValue()->getChild(1), AssertionException, 6400214); } } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_max_items_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_max_items_test.cpp index 0ce7df4d579..9e498591631 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_max_items_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_max_items_test.cpp @@ -31,6 +31,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/schema/expression_internal_schema_max_items.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -86,5 +87,14 @@ TEST(InternalSchemaMaxItemsMatchExpression, NestedArraysWorkWithDottedPaths) { ASSERT(!maxItems.matchesBSON(BSON("a" << BSON("b" << BSON_ARRAY(1 << 2 << 3))))); } +DEATH_TEST_REGEX(InternalSchemaMaxItemsMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400215") { + InternalSchemaMaxItemsMatchExpression maxItems("a", 2); + + ASSERT_EQ(maxItems.numChildren(), 0); + ASSERT_THROWS_CODE(maxItems.getChild(0), AssertionException, 6400215); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_max_properties_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_max_properties_test.cpp index 6c8327e9017..587243cb0ad 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_max_properties_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_max_properties_test.cpp @@ -32,6 +32,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/schema/expression_internal_schema_max_properties.h" #include "mongo/db/matcher/schema/expression_internal_schema_min_properties.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -89,5 +90,14 @@ TEST(InternalSchemaMaxPropertiesMatchExpression, MinPropertiesNotEquivalentToMax ASSERT_FALSE(maxProperties.equivalent(&minProperties)); } +DEATH_TEST_REGEX(InternalSchemaMaxPropertiesMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400216") { + InternalSchemaMaxPropertiesMatchExpression maxProperties(5); + + ASSERT_EQ(maxProperties.numChildren(), 0); + ASSERT_THROWS_CODE(maxProperties.getChild(0), AssertionException, 6400216); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_min_items_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_min_items_test.cpp index 7cb5af3547f..989e4ba8a0c 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_min_items_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_min_items_test.cpp @@ -30,6 +30,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/schema/expression_internal_schema_min_items.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -85,5 +86,14 @@ TEST(InternalSchemaMinItemsMatchExpression, NestedArraysWorkWithDottedPaths) { ASSERT(!minItems.matchesBSON(BSON("a" << BSON("b" << BSON_ARRAY(1))))); } +DEATH_TEST_REGEX(InternalSchemaMinItemsMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400215") { + InternalSchemaMinItemsMatchExpression minItems("a", 2); + + ASSERT_EQ(minItems.numChildren(), 0); + ASSERT_THROWS_CODE(minItems.getChild(0), AssertionException, 6400215); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_min_properties_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_min_properties_test.cpp index 8703940f525..c7abaa0c4e1 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_min_properties_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_min_properties_test.cpp @@ -32,6 +32,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/schema/expression_internal_schema_max_properties.h" #include "mongo/db/matcher/schema/expression_internal_schema_min_properties.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -81,5 +82,14 @@ TEST(InternalSchemaMinPropertiesMatchExpression, EquivalentFunctionIsAccurate) { ASSERT_FALSE(minProperties1.equivalent(&minProperties3)); } +DEATH_TEST_REGEX(InternalSchemaMinPropertiesMatchExpression, + GetChildFailsIndexGreaterThanZero, + "Tripwire assertion.*6400216") { + InternalSchemaMaxPropertiesMatchExpression minProperties(1); + + ASSERT_EQ(minProperties.numChildren(), 0); + ASSERT_THROWS_CODE(minProperties.getChild(0), AssertionException, 6400216); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_num_array_items.h b/src/mongo/db/matcher/schema/expression_internal_schema_num_array_items.h index 99ed79ec5d6..5ecf216dd60 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_num_array_items.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_num_array_items.h @@ -61,7 +61,7 @@ public: } MatchExpression* getChild(size_t i) const final { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400215); } void resetChild(size_t i, MatchExpression* other) override { diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_num_properties.h b/src/mongo/db/matcher/schema/expression_internal_schema_num_properties.h index 29fd4fc6145..11c6be03aca 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_num_properties.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_num_properties.h @@ -58,7 +58,7 @@ public: } MatchExpression* getChild(size_t i) const final { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400216); } void resetChild(size_t, MatchExpression*) override { diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_object_match.h b/src/mongo/db/matcher/schema/expression_internal_schema_object_match.h index 93b6e1b765e..6b18cd2fb46 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_object_match.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_object_match.h @@ -38,6 +38,7 @@ namespace mongo { class InternalSchemaObjectMatchExpression final : public PathMatchExpression { public: static constexpr StringData kName = "$_internalSchemaObjectMatch"_sd; + static constexpr int kNumChildren = 1; InternalSchemaObjectMatchExpression(StringData path, std::unique_ptr<MatchExpression> expr, @@ -59,17 +60,17 @@ public: size_t numChildren() const final { invariant(_sub); - return 1; + return kNumChildren; } MatchExpression* getChild(size_t i) const final { // 'i' must be 0 since there's always exactly one child. - invariant(i == 0); + tassert(6400217, "Out-of-bounds access to child of MatchExpression.", i < kNumChildren); return _sub.get(); } void resetChild(size_t i, MatchExpression* other) final override { - tassert(6329410, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); + tassert(6329410, "Out-of-bounds access to child of MatchExpression.", i < kNumChildren); _sub.reset(other); } diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_object_match_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_object_match_test.cpp index f161bbd5eb2..e3b67bd4828 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_object_match_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_object_match_test.cpp @@ -218,8 +218,8 @@ TEST(InternalSchemaObjectMatchExpression, HasSingleChild) { } DEATH_TEST_REGEX(InternalSchemaObjectMatchExpression, - GetChildFailsIndexGreaterThanZero, - "Invariant failure.*i == 0") { + GetChildFailsIndexGreaterThanOne, + "Tripwire assertion.*6400217") { auto query = fromjson( " {a: {$_internalSchemaObjectMatch: {" " c: {$eq: 3}" @@ -228,7 +228,8 @@ DEATH_TEST_REGEX(InternalSchemaObjectMatchExpression, auto objMatch = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(objMatch.getStatus()); - objMatch.getValue()->getChild(1); + ASSERT_EQ(objMatch.getValue()->numChildren(), 1); + ASSERT_THROWS_CODE(objMatch.getValue()->getChild(1), AssertionException, 6400217); } } // namespace diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq.h b/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq.h index 62dfb6d66a2..ba422253bf2 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq.h @@ -81,7 +81,7 @@ public: } MatchExpression* getChild(size_t i) const final { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400218); } void resetChild(size_t i, MatchExpression*) final override { diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq_test.cpp index fe628c66f2b..596db5a95eb 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_root_doc_eq_test.cpp @@ -33,6 +33,7 @@ #include "mongo/db/matcher/matcher.h" #include "mongo/db/matcher/schema/expression_internal_schema_root_doc_eq.h" #include "mongo/db/pipeline/expression_context_for_test.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -113,5 +114,15 @@ TEST(InternalSchemaRootDocEqMatchExpression, EquivalentToClone) { auto clone = rootDocEq.getMatchExpression()->shallowClone(); ASSERT_TRUE(rootDocEq.getMatchExpression()->equivalent(clone.get())); } + +DEATH_TEST_REGEX(InternalSchemaRootDocEqMatchExpression, + GetChildFailsIndexLargerThanZero, + "Tripwire assertion.*6400218") { + InternalSchemaRootDocEqMatchExpression rootDocEq(BSON("a" << 1 << "b" << BSON("c" << 1))); + + ASSERT_EQ(rootDocEq.numChildren(), 0); + ASSERT_THROWS_CODE(rootDocEq.getChild(0), AssertionException, 6400218); +} + } // namespace } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_unique_items.h b/src/mongo/db/matcher/schema/expression_internal_schema_unique_items.h index ddb86c89403..9693ba681e7 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_unique_items.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_unique_items.h @@ -57,7 +57,7 @@ public: } MatchExpression* getChild(size_t i) const final { - MONGO_UNREACHABLE; + MONGO_UNREACHABLE_TASSERT(6400219); } void resetChild(size_t i, MatchExpression*) final override { diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_unique_items_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_unique_items_test.cpp index 7215499b78b..70d0491a947 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_unique_items_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_unique_items_test.cpp @@ -32,6 +32,7 @@ #include "mongo/bson/json.h" #include "mongo/db/matcher/schema/expression_internal_schema_unique_items.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/unittest/death_test.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -115,5 +116,15 @@ TEST(InternalSchemaUniqueItemsMatchExpression, FindsFirstDuplicateValue) { ASSERT_FALSE(uniqueItems.findFirstDuplicateValue(fromjson("[1, 2]}"))); ASSERT_FALSE(uniqueItems.findFirstDuplicateValue(fromjson("[]}"))); } + +DEATH_TEST_REGEX(InternalSchemaUniqueItemsMatchExpression, + GetChildFailsIndexLargerThanZero, + "Tripwire assertion.*6400219") { + InternalSchemaUniqueItemsMatchExpression uniqueItems("foo"); + + ASSERT_EQ(uniqueItems.numChildren(), 0); + ASSERT_THROWS_CODE(uniqueItems.getChild(0), AssertionException, 6400219); +} + } // namespace } // namespace mongo |