diff options
author | Richard Hausman <richard.hausman@mongodb.com> | 2022-08-19 17:55:53 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-08-19 19:31:00 +0000 |
commit | d3ea0605477301d4055034dde5153267a61eb5ab (patch) | |
tree | bc1fcfa4b804ce2b713ed69f3bbc13eab897a515 /src | |
parent | 9a07ecfd7e91d330fc4cf8ea8b08e2f2e75ec04e (diff) | |
download | mongo-d3ea0605477301d4055034dde5153267a61eb5ab.tar.gz |
SERVER-67880 : Check BSON column is decompressible in the validate command.
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/bson/SConscript | 6 | ||||
-rw-r--r-- | src/mongo/bson/bson_validate.cpp | 27 | ||||
-rw-r--r-- | src/mongo/bson/bson_validate.h | 3 | ||||
-rw-r--r-- | src/mongo/bson/bson_validate_test.cpp | 121 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.cpp | 4 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.h | 5 | ||||
-rw-r--r-- | src/mongo/client/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/client/mongo_uri_test.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/SConscript | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_build_entry_test.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/storage/SConscript | 11 | ||||
-rw-r--r-- | src/mongo/db/update/document_diff_calculator_test.cpp | 11 | ||||
-rw-r--r-- | src/mongo/dbtests/jsobjtests.cpp | 31 | ||||
-rw-r--r-- | src/mongo/dbtests/jsontests.cpp | 2 | ||||
-rw-r--r-- | src/mongo/dbtests/querytests.cpp | 3 | ||||
-rw-r--r-- | src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp | 21 | ||||
-rw-r--r-- | src/mongo/util/SConscript | 1 |
19 files changed, 159 insertions, 101 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index b8bc357d941..0e831e0ff51 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -146,7 +146,6 @@ baseEnv.Library( 'base/validate_locale.cpp', 'bson/bson_comparator_interface_base.cpp', 'bson/bson_depth.cpp', - 'bson/bson_validate.cpp', 'bson/bsonelement.cpp', 'bson/bsonmisc.cpp', 'bson/bsonobj.cpp', diff --git a/src/mongo/bson/SConscript b/src/mongo/bson/SConscript index 2f5c806d6f6..8781e466f00 100644 --- a/src/mongo/bson/SConscript +++ b/src/mongo/bson/SConscript @@ -28,6 +28,8 @@ env.CppUnitTest( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/bson/bson_validate', + '$BUILD_DIR/mongo/bson/util/bson_column', ], ) @@ -38,6 +40,7 @@ env.Benchmark( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/bson/bson_validate', ], ) @@ -52,6 +55,9 @@ env.CppLibfuzzerTest( ], ) +env.Library(target='bson_validate', source=['bson_validate.cpp'], + LIBDEPS_PRIVATE=['$BUILD_DIR/mongo/bson/util/bson_column']) + asioEnv = env.Clone() asioEnv.InjectThirdParty('asio') diff --git a/src/mongo/bson/bson_validate.cpp b/src/mongo/bson/bson_validate.cpp index d1403f07bbf..f69700696b1 100644 --- a/src/mongo/bson/bson_validate.cpp +++ b/src/mongo/bson/bson_validate.cpp @@ -35,6 +35,7 @@ #include "mongo/base/data_view.h" #include "mongo/bson/bson_depth.h" #include "mongo/bson/bsonelement.h" +#include "mongo/bson/util/bsoncolumn.h" #include "mongo/logv2/log.h" #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kDefault @@ -142,13 +143,14 @@ public: l == UUIDLength); break; } - case BinDataType::MD5Type: + case BinDataType::MD5Type: { constexpr uint32_t md5Length = 16; auto md5Size = ConstDataView(ptr).read<LittleEndian<uint32_t>>(); uassert(NonConformantBSON, fmt::format("MD5 must be 16 bytes, got {} instead.", md5Size), md5Size == md5Length); break; + } } break; } @@ -222,6 +224,25 @@ class FullValidator : private ExtendedValidator { public: void checkNonConformantElem(const char* ptr, uint32_t offsetToValue, uint8_t type) { ExtendedValidator::checkNonConformantElem(ptr, offsetToValue, type); + switch (type) { + case BSONType::BinData: { + uint8_t subtype = ConstDataView(ptr + offsetToValue + sizeof(uint32_t)) + .read<LittleEndian<uint8_t>>(); + switch (subtype) { + case BinDataType::Column: { + // Check for exceptions when decompressing. + // Calling size() decompresses the entire column. + try { + BSONColumn(BSONElement(ptr)).size(); + } catch (...) { + uasserted(NonConformantBSON, + "Exception ocurred while decompressing a BSON column."); + } + break; + } + } + } + } } void checkUTF8Char() {} @@ -490,4 +511,8 @@ Status validateBSON(const char* originalBuffer, else MONGO_UNREACHABLE; } + +Status validateBSON(const BSONObj& obj, BSONValidateMode mode) { + return validateBSON(obj.objdata(), obj.objsize(), mode); +} } // namespace mongo diff --git a/src/mongo/bson/bson_validate.h b/src/mongo/bson/bson_validate.h index a748d372d39..ce79245459c 100644 --- a/src/mongo/bson/bson_validate.h +++ b/src/mongo/bson/bson_validate.h @@ -32,6 +32,7 @@ #include <cstdint> #include "mongo/base/status.h" +#include "mongo/bson/bsonobj.h" #include "mongo/bson/bsontypes.h" namespace mongo { @@ -69,4 +70,6 @@ enum class BSONValidateMode { Status validateBSON(const char* buf, uint64_t maxLength, BSONValidateMode mode = BSONValidateMode::kDefault) noexcept; + +Status validateBSON(const BSONObj& obj, BSONValidateMode mode = BSONValidateMode::kDefault); } // namespace mongo diff --git a/src/mongo/bson/bson_validate_test.cpp b/src/mongo/bson/bson_validate_test.cpp index 63a7f58056f..1c9d7b0d046 100644 --- a/src/mongo/bson/bson_validate_test.cpp +++ b/src/mongo/bson/bson_validate_test.cpp @@ -33,6 +33,7 @@ #include "mongo/base/data_view.h" #include "mongo/bson/bson_depth.h" #include "mongo/bson/bson_validate.h" +#include "mongo/bson/util/bsoncolumnbuilder.h" #include "mongo/db/jsobj.h" #include "mongo/logv2/log.h" #include "mongo/platform/random.h" @@ -57,10 +58,10 @@ void appendInvalidStringElement(const char* fieldName, BufBuilder* bb) { TEST(BSONValidate, Basic) { BSONObj x; - ASSERT_TRUE(x.valid()); + ASSERT_TRUE(validateBSON(x).isOK()); x = BSON("x" << 1); - ASSERT_TRUE(x.valid()); + ASSERT_TRUE(validateBSON(x).isOK()); } TEST(BSONValidate, RandomData) { @@ -86,12 +87,12 @@ TEST(BSONValidate, RandomData) { ASSERT_EQUALS(size, o.objsize()); - if (o.valid()) { + if (validateBSON(o).isOK()) { numValid++; jsonSize += o.jsonString().size(); - ASSERT_OK(validateBSON(o.objdata(), o.objsize())); + ASSERT_OK(validateBSON(o)); } else { - ASSERT_NOT_OK(validateBSON(o.objdata(), o.objsize())); + ASSERT_NOT_OK(validateBSON(o)); } delete[] x; @@ -137,12 +138,12 @@ TEST(BSONValidate, MuckingData1) { data[i] = 0xc8U; numToRun++; - if (mine.valid()) { + if (validateBSON(mine).isOK()) { numValid++; jsonSize += mine.jsonString().size(); - ASSERT_OK(validateBSON(mine.objdata(), mine.objsize())); + ASSERT_OK(validateBSON(mine)); } else { - ASSERT_NOT_OK(validateBSON(mine.objdata(), mine.objsize())); + ASSERT_NOT_OK(validateBSON(mine)); } } @@ -194,7 +195,7 @@ TEST(BSONValidate, Fuzz) { // to compare outputs against (BSONObj::valid() is a wrapper for validateBSON()). // Thus, the reason for this test is to ensure that validateBSON() doesn't trip // any ASAN or UBSAN check when fed fuzzed input. - validateBSON(fuzzed.objdata(), fuzzed.objsize()).isOK(); + validateBSON(fuzzed).isOK(); } } @@ -202,15 +203,15 @@ TEST(BSONValidateExtended, MD5Size) { // 16 byte string. auto properSizeMD5 = "aaaaaaaaaaaaaaaa"; BSONObj x1 = BSON("md5" << BSONBinData(properSizeMD5, 16, MD5Type)); - ASSERT_OK(validateBSON(x1.objdata(), x1.objsize(), mongo::BSONValidateMode::kExtended)); - ASSERT_OK(validateBSON(x1.objdata(), x1.objsize(), mongo::BSONValidateMode::kFull)); + ASSERT_OK(validateBSON(x1, mongo::BSONValidateMode::kExtended)); + ASSERT_OK(validateBSON(x1, mongo::BSONValidateMode::kFull)); // 15 byte string. auto improperSizeMD5 = "aaaaaaaaaaaaaaa"; BSONObj x2 = BSON("md5" << BSONBinData(improperSizeMD5, 15, MD5Type)); - Status status = validateBSON(x2.objdata(), x2.objsize(), mongo::BSONValidateMode::kExtended); + Status status = validateBSON(x2, mongo::BSONValidateMode::kExtended); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); - status = validateBSON(x2.objdata(), x2.objsize(), mongo::BSONValidateMode::kFull); + status = validateBSON(x2, mongo::BSONValidateMode::kFull); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); } @@ -334,23 +335,23 @@ TEST(BSONValidateExtended, BSONArrayIndexes) { TEST(BSONValidateFast, Empty) { BSONObj x; - ASSERT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_OK(validateBSON(x)); } TEST(BSONValidateFast, RegEx) { BSONObjBuilder b; b.appendRegex("foo", "i"); BSONObj x = b.obj(); - ASSERT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_OK(validateBSON(x)); } TEST(BSONValidateFast, Simple0) { BSONObj x; - ASSERT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_OK(validateBSON(x)); x = BSON("foo" << 17 << "bar" << "eliot"); - ASSERT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_OK(validateBSON(x)); } TEST(BSONValidateFast, Simple2) { @@ -362,7 +363,7 @@ TEST(BSONValidateFast, Simple2) { sprintf(buf, "bar%d", i); b.appendMaxForType(buf, i); BSONObj x = b.obj(); - ASSERT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_OK(validateBSON(x)); } } @@ -377,14 +378,14 @@ TEST(BSONValidateFast, Simple3) { b.appendMaxForType(buf, i); } BSONObj x = b.obj(); - ASSERT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_OK(validateBSON(x)); } TEST(BSONValidateFast, NestedObject) { BSONObj x = BSON("a" << 1 << "b" << BSON("c" << 2 << "d" << BSONArrayBuilder().obj() << "e" << BSON_ARRAY("1" << 2 << 3))); - ASSERT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_OK(validateBSON(x)); ASSERT_NOT_OK(validateBSON(x.objdata(), x.objsize() / 2)); } @@ -413,7 +414,7 @@ TEST(BSONValidateFast, AllTypesSimple) { << "18long" << 0x0123456789abcdefll // 64-bit integer << "19decimal" << Decimal128("0.30") // 128-bit decimal floating point ); - ASSERT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_OK(validateBSON(x)); } TEST(BSONValidateFast, ErrorWithId) { @@ -422,7 +423,7 @@ TEST(BSONValidateFast, ErrorWithId) { ob.append("_id", 1); appendInvalidStringElement("not_id", &bb); const BSONObj x = ob.done(); - const Status status = validateBSON(x.objdata(), x.objsize()); + const Status status = validateBSON(x); ASSERT_NOT_OK(status); ASSERT_EQUALS( status.reason(), @@ -435,7 +436,7 @@ TEST(BSONValidateFast, ErrorBeforeId) { appendInvalidStringElement("not_id", &bb); ob.append("_id", 1); const BSONObj x = ob.done(); - const Status status = validateBSON(x.objdata(), x.objsize()); + const Status status = validateBSON(x); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "Not null terminated string in element with field name 'not_id' in object with " @@ -447,7 +448,7 @@ TEST(BSONValidateFast, ErrorNoId) { BSONObjBuilder ob(bb); appendInvalidStringElement("not_id", &bb); const BSONObj x = ob.done(); - const Status status = validateBSON(x.objdata(), x.objsize()); + const Status status = validateBSON(x); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "Not null terminated string in element with field name 'not_id' in object with " @@ -459,7 +460,7 @@ TEST(BSONValidateFast, ErrorIsInId) { BSONObjBuilder ob(bb); appendInvalidStringElement("_id", &bb); const BSONObj x = ob.done(); - const Status status = validateBSON(x.objdata(), x.objsize()); + const Status status = validateBSON(x); ASSERT_NOT_OK(status); ASSERT_EQUALS( status.reason(), @@ -474,7 +475,7 @@ TEST(BSONValidateFast, NonTopLevelId) { << "not the real _id")); appendInvalidStringElement("not_id2", &bb); const BSONObj x = ob.done(); - const Status status = validateBSON(x.objdata(), x.objsize()); + const Status status = validateBSON(x); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "Not null terminated string in element with field name 'not_id2' in object with " @@ -490,7 +491,7 @@ TEST(BSONValidateFast, ErrorInNestedObjectWithId) { const BSONObj x = BSON("_id" << 1 << "nested" << BSON_ARRAY("a" << "b" << nestedInvalid)); - const Status status = validateBSON(x.objdata(), x.objsize()); + const Status status = validateBSON(x); ASSERT_NOT_OK(status); ASSERT_EQUALS(status.reason(), "Not null terminated string in element with field name 'nested.2.invalid' " @@ -510,14 +511,14 @@ TEST(BSONValidateFast, StringHasSomething) { + 4 // size , x.objsize()); - ASSERT_NOT_OK(validateBSON(x.objdata(), x.objsize())); + ASSERT_NOT_OK(validateBSON(x)); } TEST(BSONValidateFast, BoolValuesAreValidated) { BSONObjBuilder bob; bob.append("x", false); const BSONObj obj = bob.done(); - ASSERT_OK(validateBSON(obj.objdata(), obj.objsize())); + ASSERT_OK(validateBSON(obj)); const BSONElement x = obj["x"]; // Legal, because we know that the BufBuilder gave // us back some heap memory, which isn't oringinally const. @@ -527,9 +528,9 @@ TEST(BSONValidateFast, BoolValuesAreValidated) { ++val) { *writable = static_cast<char>(val); if ((val == 0) || (val == 1)) { - ASSERT_OK(validateBSON(obj.objdata(), obj.objsize())); + ASSERT_OK(validateBSON(obj)); } else { - ASSERT_NOT_OK(validateBSON(obj.objdata(), obj.objsize())); + ASSERT_NOT_OK(validateBSON(obj)); } } } @@ -542,7 +543,7 @@ TEST(BSONValidateFast, InvalidType) { BSONObj obj(buffer); // Validate fails. - ASSERT_NOT_OK(validateBSON(obj.objdata(), obj.objsize())); + ASSERT_NOT_OK(validateBSON(obj)); // Make sure the binary buffer above indeed has the invalid type. ASSERT_THROWS_CODE(obj.woCompare(BSON("A" << 1)), DBException, 10320); @@ -550,9 +551,9 @@ TEST(BSONValidateFast, InvalidType) { TEST(BSONValidateFast, ValidCodeWScope) { BSONObj obj = BSON("a" << BSONCodeWScope("code", BSON("c" << BSONObj()))); - ASSERT_OK(validateBSON(obj.objdata(), obj.objsize())); + ASSERT_OK(validateBSON(obj)); obj = BSON("a" << BSONCodeWScope("code", BSON("c" << BSONArray() << "d" << BSONArray()))); - ASSERT_OK(validateBSON(obj.objdata(), obj.objsize())); + ASSERT_OK(validateBSON(obj)); } BSONObj nest(int nesting) { @@ -561,10 +562,10 @@ BSONObj nest(int nesting) { TEST(BSONValidateFast, MaxNestingDepth) { BSONObj maxNesting = nest(BSONDepth::getMaxAllowableDepth()); - ASSERT_OK(validateBSON(maxNesting.objdata(), maxNesting.objsize())); + ASSERT_OK(validateBSON(maxNesting)); BSONObj tooDeepNesting = nest(BSONDepth::getMaxAllowableDepth() + 1); - Status status = validateBSON(tooDeepNesting.objdata(), tooDeepNesting.objsize()); + Status status = validateBSON(tooDeepNesting); ASSERT_EQ(status.code(), ErrorCodes::Overflow); } @@ -601,8 +602,8 @@ TEST(BSONValidateExtended, UUIDLength) { // Checks that an invalid UUID length (!= 16 bytes) throws a warning. std::pair<Status, Status> stats{Status::OK(), Status::OK()}; auto fullyValidate = [&](BSONObj obj) { - return std::pair{validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kExtended), - validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kFull)}; + return std::pair{validateBSON(obj, BSONValidateMode::kExtended), + validateBSON(obj, BSONValidateMode::kFull)}; }; BSONObj x = BSON("u" << BSONBinData("de", 2, BinDataType::newUUID)); stats = fullyValidate(x); @@ -622,39 +623,59 @@ TEST(BSONValidateExtended, UUIDLength) { TEST(BSONValidateExtended, DeprecatedTypes) { BSONObj obj = BSON("a" << BSONUndefined); - Status status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kExtended); + Status status = validateBSON(obj, BSONValidateMode::kExtended); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kFull); + status = validateBSON(obj, BSONValidateMode::kFull); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); obj = BSON("b" << BSONDBRef("db", OID("dbdbdbdbdbdbdbdbdbdbdbdb"))); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kExtended); + status = validateBSON(obj, BSONValidateMode::kExtended); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kFull); + status = validateBSON(obj, BSONValidateMode::kFull); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); obj = BSON("c" << BSONSymbol("symbol")); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kExtended); + status = validateBSON(obj, BSONValidateMode::kExtended); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kFull); + status = validateBSON(obj, BSONValidateMode::kFull); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); obj = BSON("d" << BSONCodeWScope("(function(){})();", BSON("a" << 1))); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kExtended); + status = validateBSON(obj, BSONValidateMode::kExtended); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kFull); + status = validateBSON(obj, BSONValidateMode::kFull); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); obj = BSON("e" << BSONBinData("", 0, ByteArrayDeprecated)); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kExtended); + status = validateBSON(obj, BSONValidateMode::kExtended); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kFull); + status = validateBSON(obj, BSONValidateMode::kFull); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); obj = BSON("f" << BSONBinData("", 0, bdtUUID)); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kExtended); + status = validateBSON(obj, BSONValidateMode::kExtended); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); - status = validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kFull); + status = validateBSON(obj, BSONValidateMode::kFull); ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); } + +TEST(BSONValidateExtended, BSONColumn) { + BSONColumnBuilder cb("example"_sd); + cb.append(BSON("a" + << "deadbeef") + .getField("a")); + BSONBinData columnData = cb.finalize(); + BSONObj obj = BSON("a" << columnData); + Status status = validateBSON(obj, BSONValidateMode::kFull); + ASSERT_OK(status); + + // Change one important byte. + ((char*)columnData.data)[0] = '0'; + obj = BSON("a" << columnData); + status = validateBSON(obj, BSONValidateMode::kExtended); + ASSERT_OK(status); + status = validateBSON(obj, BSONValidateMode::kFull); + ASSERT_EQ(status.code(), ErrorCodes::NonConformantBSON); +} + } // namespace diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp index 6566398a883..0149eeece7d 100644 --- a/src/mongo/bson/bsonobj.cpp +++ b/src/mongo/bson/bsonobj.cpp @@ -32,7 +32,6 @@ #include "mongo/db/jsobj.h" #include "mongo/base/data_range.h" -#include "mongo/bson/bson_validate.h" #include "mongo/bson/bsonelement_comparator_interface.h" #include "mongo/bson/generator_extended_canonical_2_0_0.h" #include "mongo/bson/generator_extended_relaxed_2_0_0.h" @@ -300,9 +299,6 @@ BSONObj BSONObj::jsonStringBuffer(JsonStringFormat format, } } -bool BSONObj::valid() const { - return validateBSON(objdata(), objsize()).isOK(); -} int BSONObj::woCompare(const BSONObj& r, const Ordering& o, diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h index a5270adfd25..1a51b370678 100644 --- a/src/mongo/bson/bsonobj.h +++ b/src/mongo/bson/bsonobj.h @@ -638,11 +638,6 @@ public: bool hasFieldNames() const; /** - * Returns true if this object is valid and returns false otherwise. - */ - bool valid() const; - - /** * add all elements of the object to the specified vector */ void elems(std::vector<BSONElement>&) const; diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript index 25df63559cc..cd21400ca2b 100644 --- a/src/mongo/client/SConscript +++ b/src/mongo/client/SConscript @@ -71,6 +71,7 @@ if get_option('ssl') == 'on': ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/bson/bson_validate', '$BUILD_DIR/mongo/db/server_options_core', # For object_check.h '$BUILD_DIR/mongo/idl/idl_parser', '$BUILD_DIR/third_party/shim_kms_message', diff --git a/src/mongo/client/mongo_uri_test.cpp b/src/mongo/client/mongo_uri_test.cpp index f0cb567b75d..2555121ae0f 100644 --- a/src/mongo/client/mongo_uri_test.cpp +++ b/src/mongo/client/mongo_uri_test.cpp @@ -33,6 +33,7 @@ #include <fstream> #include "mongo/base/string_data.h" +#include "mongo/bson/bson_validate.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsontypes.h" #include "mongo/bson/json.h" @@ -583,7 +584,7 @@ BSONObj getBsonFromJsonFile(std::string fileName) { std::ifstream infile(filename.c_str()); std::string data((std::istreambuf_iterator<char>(infile)), std::istreambuf_iterator<char>()); BSONObj obj = fromjson(data); - ASSERT_TRUE(obj.valid()); + ASSERT_TRUE(validateBSON(obj).isOK()); ASSERT_TRUE(obj.hasField("tests")); BSONObj arr = obj.getField("tests").embeddedObject().getOwned(); ASSERT_TRUE(arr.couldBeArray()); diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 4f3c7fef780..200c6878ab7 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -277,6 +277,7 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/bson/bson_validate', ], ) @@ -292,6 +293,7 @@ env.Library( 'server_options_core', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/bson/bson_validate', '$BUILD_DIR/mongo/idl/server_parameter', '$BUILD_DIR/mongo/util/fail_point', '$BUILD_DIR/mongo/util/options_parser/options_parser', @@ -600,6 +602,7 @@ env.Library( 'write_concern_options', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/bson/bson_validate', '$BUILD_DIR/mongo/db/storage/storage_change_lock', '$BUILD_DIR/mongo/util/processinfo', ], @@ -997,6 +1000,7 @@ env.Library( '$BUILD_DIR/mongo/base', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/bson/bson_validate', '$BUILD_DIR/mongo/db/audit', '$BUILD_DIR/mongo/db/auth/auth', '$BUILD_DIR/mongo/db/auth/auth_umc', @@ -1297,6 +1301,7 @@ env.Library( '$BUILD_DIR/mongo/base', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/bson/bson_validate', '$BUILD_DIR/mongo/db/catalog/clustered_collection_options', '$BUILD_DIR/mongo/db/query/collation/collator_interface', '$BUILD_DIR/mongo/db/storage/key_string', diff --git a/src/mongo/db/catalog/index_build_entry_test.cpp b/src/mongo/db/catalog/index_build_entry_test.cpp index 6aa53a8a2ba..dc0972f3085 100644 --- a/src/mongo/db/catalog/index_build_entry_test.cpp +++ b/src/mongo/db/catalog/index_build_entry_test.cpp @@ -32,6 +32,7 @@ #include <string> #include <vector> +#include "mongo/bson/bson_validate.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/bsontypes.h" @@ -124,7 +125,7 @@ TEST(IndexBuildEntryTest, SerializeAndDeserialize) { entry.setCommitReadyMembers(generateCommitReadyMembers(3)); BSONObj obj = entry.toBSON(); - ASSERT_TRUE(obj.valid()); + ASSERT_TRUE(validateBSON(obj).isOK()); IDLParserContext ctx("IndexBuildsEntry Parser"); IndexBuildEntry rebuiltEntry = IndexBuildEntry::parse(ctx, obj); diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index d058ade3878..f25afb27939 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -514,6 +514,7 @@ env.Library( 'shutdown.idl', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/bson/bson_validate', '$BUILD_DIR/mongo/idl/idl_parser', '$BUILD_DIR/mongo/util/fail_point', ], diff --git a/src/mongo/db/storage/SConscript b/src/mongo/db/storage/SConscript index 86c58de6253..0aeb72b0d83 100644 --- a/src/mongo/db/storage/SConscript +++ b/src/mongo/db/storage/SConscript @@ -383,16 +383,15 @@ env.Library( ) env.Library( - target='storage_engine_metadata', - source=[ + target='storage_engine_metadata', source=[ 'storage_engine_metadata.cpp', - ], - LIBDEPS=[ + ], LIBDEPS=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/bson/dotted_path_support', '$BUILD_DIR/mongo/db/server_options_core', - ], -) + ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/bson/bson_validate', + ]) env.Library( target='storage_file_util', diff --git a/src/mongo/db/update/document_diff_calculator_test.cpp b/src/mongo/db/update/document_diff_calculator_test.cpp index 55a05051021..feaeb9343be 100644 --- a/src/mongo/db/update/document_diff_calculator_test.cpp +++ b/src/mongo/db/update/document_diff_calculator_test.cpp @@ -32,6 +32,7 @@ #include <functional> #include "mongo/bson/bson_depth.h" +#include "mongo/bson/bson_validate.h" #include "mongo/bson/json.h" #include "mongo/db/update/document_diff_calculator.h" #include "mongo/unittest/unittest.h" @@ -295,7 +296,7 @@ TEST(DocumentDiffCalculatorTest, DeeplyNestObjectGenerateDiff) { preBob.append("largeField", largeValue); buildDeepObj(&preBob, "subObj", 0, maxDepth, functionToApply); auto preObj = preBob.done(); - ASSERT(preObj.valid()); + ASSERT_OK(validateBSON(preObj)); BSONObjBuilder postBob; postBob.append("largeField", largeValue); @@ -312,7 +313,7 @@ TEST(DocumentDiffCalculatorTest, DeeplyNestObjectGenerateDiff) { // Deleting the deepest field should give the post object. diffOutput = doc_diff::computeDiff(preObj, postBob2.done(), 0, nullptr); ASSERT(diffOutput); - ASSERT(diffOutput->diff.valid()); + ASSERT_OK(validateBSON(diffOutput->diff)); BSONObjBuilder expectedOutputBuilder; buildDeepObj(&expectedOutputBuilder, @@ -341,17 +342,17 @@ TEST(DocumentDiffCalculatorTest, DeepestObjectSubDiff) { value = 1; buildDeepObj(&bob1, "subObj", 0, BSONDepth::getMaxDepthForUserStorage(), functionToApply); auto preObj = bob1.done(); - ASSERT(preObj.valid()); + ASSERT_OK(validateBSON(preObj)); BSONObjBuilder postBob; value = 2; buildDeepObj(&postBob, "subObj", 0, BSONDepth::getMaxDepthForUserStorage(), functionToApply); auto postObj = postBob.done(); - ASSERT(postObj.valid()); + ASSERT_OK(validateBSON(postObj)); auto diffOutput = doc_diff::computeDiff(preObj, postObj, 0, nullptr); ASSERT(diffOutput); - ASSERT(diffOutput->diff.valid()); + ASSERT_OK(validateBSON(diffOutput->diff)); BSONObjBuilder expectedOutputBuilder; buildDeepObj(&expectedOutputBuilder, diff --git a/src/mongo/dbtests/jsobjtests.cpp b/src/mongo/dbtests/jsobjtests.cpp index a79bf0bbf9b..37da3d64aa7 100644 --- a/src/mongo/dbtests/jsobjtests.cpp +++ b/src/mongo/dbtests/jsobjtests.cpp @@ -37,6 +37,7 @@ #include <cmath> #include <iostream> +#include "mongo/bson/bson_validate.h" #include "mongo/bson/bsonobj_comparator.h" #include "mongo/bson/simple_bsonelement_comparator.h" #include "mongo/bson/util/builder.h" @@ -507,7 +508,7 @@ public: bb << "a" << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + 4) + 1); - ASSERT(tmp.valid()); + ASSERT(validateBSON(tmp).isOK()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT_BSONOBJ_EQ(tmp, BSON("a" << 1)); @@ -515,7 +516,7 @@ public: bb << "b" << 2; BSONObj obj = bb.obj(); ASSERT_EQUALS(obj.objsize(), 4 + (1 + 2 + 4) + (1 + 2 + 4) + 1); - ASSERT(obj.valid()); + ASSERT(validateBSON(obj).isOK()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1 << "b" << 2)); @@ -525,7 +526,7 @@ public: bb << "a" << GT << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + 1); - ASSERT(tmp.valid()); + ASSERT(validateBSON(tmp).isOK()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT_BSONOBJ_EQ(tmp, BSON("a" << BSON("$gt" << 1))); @@ -534,7 +535,7 @@ public: BSONObj obj = bb.obj(); ASSERT(obj.objsize() == 4 + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + (1 + 2 + (4 + 1 + 4 + 4 + 1)) + 1); - ASSERT(obj.valid()); + ASSERT(validateBSON(obj).isOK()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); ASSERT_BSONOBJ_EQ(obj, BSON("a" << BSON("$gt" << 1) << "b" << BSON("$lt" << 2))); @@ -544,7 +545,7 @@ public: bb << "a" << 1; BSONObj tmp = bb.asTempObj(); ASSERT(tmp.objsize() == 4 + (1 + 2 + 4) + 1); - ASSERT(tmp.valid()); + ASSERT(validateBSON(tmp).isOK()); ASSERT(tmp.hasField("a")); ASSERT(!tmp.hasField("b")); ASSERT_BSONOBJ_EQ(tmp, BSON("a" << 1)); @@ -556,7 +557,7 @@ public: } bb << "b" << arr.arr(); BSONObj obj = bb.obj(); - ASSERT(obj.valid()); + ASSERT(validateBSON(obj).isOK()); ASSERT(obj.hasField("a")); ASSERT(obj.hasField("b")); } @@ -758,8 +759,8 @@ class Base { public: virtual ~Base() {} void run() { - ASSERT(valid().valid()); - ASSERT(!invalid().valid()); + ASSERT(validateBSON(valid()).isOK()); + ASSERT(!validateBSON(invalid()).isOK()); } protected: @@ -808,7 +809,7 @@ public: b.appendNull("a"); BSONObj o = b.done(); set(o, 4, mongo::Undefined); - ASSERT(o.valid()); + ASSERT(validateBSON(o).isOK()); } }; @@ -992,7 +993,7 @@ public: void run() { const char data[] = {0x07, 0x00, 0x00, 0x00, char(type_), 'a', 0x00}; BSONObj o(data); - ASSERT(!o.valid()); + ASSERT(!validateBSON(o).isOK()); } private: @@ -1331,7 +1332,7 @@ public: b2.done(); b1.append("f", 10.0); BSONObj ret = b1.done(); - ASSERT(ret.valid()); + ASSERT(validateBSON(ret).isOK()); ASSERT(ret.woCompare(fromjson("{a:'bcd',foo:{ggg:44},f:10}")) == 0); } }; @@ -1352,7 +1353,7 @@ public: BSONObj o = BSON("now" << DATENOW); Date_t after = jsTime(); - ASSERT(o.valid()); + ASSERT(validateBSON(o).isOK()); BSONElement e = o["now"]; ASSERT(e.type() == Date); @@ -1370,7 +1371,7 @@ public: b.appendTimeT("now", aTime); BSONObj o = b.obj(); - ASSERT(o.valid()); + ASSERT(validateBSON(o).isOK()); BSONElement e = o["now"]; ASSERT_EQUALS(Date, e.type()); @@ -1384,8 +1385,8 @@ public: BSONObj min = BSON("a" << MINKEY); BSONObj max = BSON("b" << MAXKEY); - ASSERT(min.valid()); - ASSERT(max.valid()); + ASSERT(validateBSON(min).isOK()); + ASSERT(validateBSON(max).isOK()); BSONElement minElement = min["a"]; BSONElement maxElement = max["b"]; diff --git a/src/mongo/dbtests/jsontests.cpp b/src/mongo/dbtests/jsontests.cpp index 7fd425e3ad7..125e7ae63c5 100644 --- a/src/mongo/dbtests/jsontests.cpp +++ b/src/mongo/dbtests/jsontests.cpp @@ -625,7 +625,7 @@ void assertEquals(const std::string& json, } void checkEquivalence(const std::string& json, const BSONObj& bson) { - ASSERT(fromjson(json).valid()); + ASSERT(validateBSON(fromjson(json)).isOK()); assertEquals(json, bson, fromjson(json), "mode: json-to-bson"); assertEquals(json, bson, fromjson(tojson(bson)), "mode: <default>"); assertEquals(json, bson, fromjson(tojson(bson, LegacyStrict)), "mode: strict"); diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp index 1e5407d62b5..677764e3d3b 100644 --- a/src/mongo/dbtests/querytests.cpp +++ b/src/mongo/dbtests/querytests.cpp @@ -30,6 +30,7 @@ #include <boost/optional.hpp> #include <iostream> +#include "mongo/bson/bson_validate.h" #include "mongo/client/dbclient_cursor.h" #include "mongo/db/catalog/collection_write_path.h" #include "mongo/db/catalog/multi_index_block.h" @@ -1204,7 +1205,7 @@ public: std::unique_ptr<DBClientCursor> cursor = _client.find(std::move(findRequest)); while (cursor->more()) { BSONObj o = cursor->next(); - verify(o.valid()); + verify(validateBSON(o).isOK()); } } void run() { diff --git a/src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp b/src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp index c875b0d16b0..d094003f515 100644 --- a/src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp +++ b/src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp @@ -35,6 +35,7 @@ #include <yaml-cpp/yaml.h> #include "mongo/base/initializer.h" +#include "mongo/bson/bson_validate.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/db/commands/test_commands_enabled.h" #include "mongo/db/json.h" @@ -195,7 +196,7 @@ protected: // convert the message into an OpMessage to examine its BSON auto outputOpMsg = mongo::OpMsg::parseOwned(outputMessage); - ASSERT(outputOpMsg.body.valid()); + ASSERT_OK(validateBSON(outputOpMsg.body)); return outputOpMsg.body; } @@ -408,7 +409,7 @@ TEST_F(MongodbCAPITest, ReadDB) { auto outputBSON = performRpc(client, findMsg); - ASSERT(outputBSON.valid()); + ASSERT_OK(validateBSON(outputBSON)); ASSERT(outputBSON.hasField("cursor")); ASSERT(outputBSON.getField("cursor").embeddedObject().hasField("firstBatch")); mongo::BSONObj arrObj = @@ -433,7 +434,7 @@ TEST_F(MongodbCAPITest, InsertAndRead) { "{insert: 'collection_name', documents: [{firstName: 'Mongo', lastName: 'DB', age: 10}]}"); auto insertOpMsg = mongo::OpMsgRequest::fromDBAndBody("db_name", insertObj); auto outputBSON1 = performRpc(client, insertOpMsg); - ASSERT(outputBSON1.valid()); + ASSERT_OK(validateBSON(outputBSON1)); ASSERT(outputBSON1.hasField("n")); ASSERT(outputBSON1.getIntField("n") == 1); ASSERT(outputBSON1.hasField("ok")); @@ -442,7 +443,7 @@ TEST_F(MongodbCAPITest, InsertAndRead) { mongo::BSONObj findObj = mongo::fromjson("{find: 'collection_name', limit: 1}"); auto findMsg = mongo::OpMsgRequest::fromDBAndBody("db_name", findObj); auto outputBSON2 = performRpc(client, findMsg); - ASSERT(outputBSON2.valid()); + ASSERT_OK(validateBSON(outputBSON2)); ASSERT(outputBSON2.hasField("cursor")); ASSERT(outputBSON2.getField("cursor").embeddedObject().hasField("firstBatch")); mongo::BSONObj arrObj = @@ -468,7 +469,7 @@ TEST_F(MongodbCAPITest, InsertAndReadDifferentClients) { "{insert: 'collection_name', documents: [{firstName: 'Mongo', lastName: 'DB', age: 10}]}"); auto insertOpMsg = mongo::OpMsgRequest::fromDBAndBody("db_name", insertObj); auto outputBSON1 = performRpc(client1, insertOpMsg); - ASSERT(outputBSON1.valid()); + ASSERT_OK(validateBSON(outputBSON1)); ASSERT(outputBSON1.hasField("n")); ASSERT(outputBSON1.getIntField("n") == 1); ASSERT(outputBSON1.hasField("ok")); @@ -477,7 +478,7 @@ TEST_F(MongodbCAPITest, InsertAndReadDifferentClients) { mongo::BSONObj findObj = mongo::fromjson("{find: 'collection_name', limit: 1}"); auto findMsg = mongo::OpMsgRequest::fromDBAndBody("db_name", findObj); auto outputBSON2 = performRpc(client2, findMsg); - ASSERT(outputBSON2.valid()); + ASSERT_OK(validateBSON(outputBSON2)); ASSERT(outputBSON2.hasField("cursor")); ASSERT(outputBSON2.getField("cursor").embeddedObject().hasField("firstBatch")); mongo::BSONObj arrObj = @@ -502,7 +503,7 @@ TEST_F(MongodbCAPITest, InsertAndDelete) { "age: 10}]}"); auto insertOpMsg = mongo::OpMsgRequest::fromDBAndBody("db_name", insertObj); auto outputBSON1 = performRpc(client, insertOpMsg); - ASSERT(outputBSON1.valid()); + ASSERT_OK(validateBSON(outputBSON1)); ASSERT(outputBSON1.hasField("n")); ASSERT(outputBSON1.getIntField("n") == 1); ASSERT(outputBSON1.hasField("ok")); @@ -515,7 +516,7 @@ TEST_F(MongodbCAPITest, InsertAndDelete) { "1}]}"); auto deleteOpMsg = mongo::OpMsgRequest::fromDBAndBody("db_name", deleteObj); auto outputBSON2 = performRpc(client, deleteOpMsg); - ASSERT(outputBSON2.valid()); + ASSERT_OK(validateBSON(outputBSON2)); ASSERT(outputBSON2.hasField("n")); ASSERT(outputBSON2.getIntField("n") == 1); ASSERT(outputBSON2.hasField("ok")); @@ -531,7 +532,7 @@ TEST_F(MongodbCAPITest, InsertAndUpdate) { "age: 10}]}"); auto insertOpMsg = mongo::OpMsgRequest::fromDBAndBody("db_name", insertObj); auto outputBSON1 = performRpc(client, insertOpMsg); - ASSERT(outputBSON1.valid()); + ASSERT_OK(validateBSON(outputBSON1)); ASSERT(outputBSON1.hasField("n")); ASSERT(outputBSON1.getIntField("n") == 1); ASSERT(outputBSON1.hasField("ok")); @@ -544,7 +545,7 @@ TEST_F(MongodbCAPITest, InsertAndUpdate) { "{age: 5}}}]}"); auto updateOpMsg = mongo::OpMsgRequest::fromDBAndBody("db_name", updateObj); auto outputBSON2 = performRpc(client, updateOpMsg); - ASSERT(outputBSON2.valid()); + ASSERT_OK(validateBSON(outputBSON2)); ASSERT(outputBSON2.hasField("ok")); ASSERT(outputBSON2.getField("ok").numberDouble() == 1.0); ASSERT(outputBSON2.hasField("nModified")); diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 55a2d9b2a74..21ae0493f40 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -225,6 +225,7 @@ env.Library( ], LIBDEPS=[ "$BUILD_DIR/mongo/base", + '$BUILD_DIR/mongo/bson/bson_validate', "$BUILD_DIR/mongo/idl/server_parameter", ], ) |