From 91b7243ea143ee56a0c098b8d5226b68fe682a39 Mon Sep 17 00:00:00 2001 From: David Percy Date: Mon, 10 Jan 2022 19:05:31 +0000 Subject: SERVER-62481 Fix crash in $_internalBucketGeoWithin parser --- .../timeseries_internal_bucket_geo_within.js | 33 +++++++++++++++++++++- src/mongo/db/matcher/expression_parser.cpp | 8 +++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/jstests/core/timeseries/timeseries_internal_bucket_geo_within.js b/jstests/core/timeseries/timeseries_internal_bucket_geo_within.js index 2354b62f326..b4b7f083552 100644 --- a/jstests/core/timeseries/timeseries_internal_bucket_geo_within.js +++ b/jstests/core/timeseries/timeseries_internal_bucket_geo_within.js @@ -274,4 +274,35 @@ results = coll.aggregate(pipeline).toArray(); assert.sameMembers(results, [ {_id: 3, a: 4, x: {y: {type: "Point", coordinates: [2, 1]}}, time: now, meta: {sensorId: 100}} ]); -}()); \ No newline at end of file + +// Test some parse errors. +{ + coll.drop(); + + pipeline = [{$match: {$_internalBucketGeoWithin: {}}}]; + let err = assert.throws(() => coll.explain().aggregate(pipeline)); + assert.eq(err.code, ErrorCodes.FailedToParse, err); + + pipeline = [{ + $match: { + $_internalBucketGeoWithin: { + withinRegion: 7, + field: 'loc', + } + } + }]; + err = assert.throws(() => coll.explain().aggregate(pipeline)); + assert.eq(err.code, ErrorCodes.TypeMismatch, err); + + pipeline = [{ + $match: { + $_internalBucketGeoWithin: { + withinRegion: {}, + field: 'loc', + } + } + }]; + err = assert.throws(() => coll.explain().aggregate(pipeline)); + assert.eq(err.code, ErrorCodes.BadValue, err); +} +}()); diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index e5dd4c3816f..0e86cd4e06b 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -1037,7 +1037,7 @@ StatusWithMatchExpression parseInternalBucketGeoWithinMatchExpression( auto subobj = elem.embeddedObject(); - std::shared_ptr geoContainer = std::make_shared(); + std::shared_ptr geoContainer; if (!subobj.hasField("withinRegion") || !subobj.hasField("field")) { return {ErrorCodes::FailedToParse, str::stream() << InternalBucketGeoWithinMatchExpression::kName @@ -1055,10 +1055,16 @@ StatusWithMatchExpression parseInternalBucketGeoWithinMatchExpression( while (geoIt.more()) { BSONElement elt = geoIt.next(); // The element must be a geo specifier. "$box", "$center", "$geometry", etc. + geoContainer = std::make_shared(); Status status = geoContainer->parseFromQuery(elt); if (!status.isOK()) return status; } + if (!geoContainer) { + return Status(ErrorCodes::BadValue, + str::stream() << InternalBucketGeoWithinMatchExpression::kName + << "'s 'withinRegion' can't be an empty object"); + } if (subobj["field"].type() != BSONType::String) { return {ErrorCodes::TypeMismatch, -- cgit v1.2.1