diff options
-rw-r--r-- | jstests/core/geo_near_bounds_overflow.js | 49 | ||||
-rw-r--r-- | jstests/libs/geo_near_random.js | 20 | ||||
-rw-r--r-- | src/mongo/db/geo/hash.cpp | 13 |
3 files changed, 72 insertions, 10 deletions
diff --git a/jstests/core/geo_near_bounds_overflow.js b/jstests/core/geo_near_bounds_overflow.js new file mode 100644 index 00000000000..04f5a977de6 --- /dev/null +++ b/jstests/core/geo_near_bounds_overflow.js @@ -0,0 +1,49 @@ +// Tests behavior with invalid 2d bounds. +(function() { +"use strict"; + +load('jstests/libs/geo_near_random.js'); + +const test = new GeoNearRandomTest('geo_near_bounds_overflow'); + +function testBounds(min, max) { + const indexBounds = {min: min, max: max}; + test.insertPts(50, indexBounds, 1, true); + + // Handle case where either 1. indexLambda will fail but not throw. We are asserting it + // works, so the outer lambda generates an exception. 2. indexLambda itself will throw. + const indexLambda = function(t) { + return t.ensureIndex({loc: '2d'}, indexBounds); + }; + const assertLambda = function(t, lambda) { + assert.commandWorked(lambda(t)); + }; + assert.throws(assertLambda, [test.t, indexLambda]); + + test.reset(); +} + +// Test max = Inf. +testBounds(-Math.pow(2, 34), Math.pow(-2147483648, 34)); + +// Test min = -Inf. +testBounds(-Math.pow(-2147483648, 34), 1); + +// Test min = -Inf and max = Inf. +testBounds(-Math.pow(-2147483648, 34), Math.pow(-2147483648, 34)); + +// Test min = Nan. +testBounds({min: 0 / 0, max: 1}); + +// Test max = Nan. +testBounds({min: 1, max: 0 / 0}); + +// Test min and max = Nan. +testBounds({min: 0 / 0, max: 0 / 0}); + +// Test min > max. +testBounds({min: 1, max: -1}); + +// Test min and max very close together. +testBounds({min: 0, max: 5.56268e-309}); +}());
\ No newline at end of file diff --git a/jstests/libs/geo_near_random.js b/jstests/libs/geo_near_random.js index b17ddabc1a4..193809cd5db 100644 --- a/jstests/libs/geo_near_random.js +++ b/jstests/libs/geo_near_random.js @@ -2,13 +2,15 @@ GeoNearRandomTest = function(name, dbToUse) { this.name = name; this.db = (dbToUse || db); this.t = this.db[name]; - this.nPts = 0; + this.reset(); + print("Starting getNear test: " + name); +}; +GeoNearRandomTest.prototype.reset = function reset() { // Reset state + this.nPts = 0; this.t.drop(); Random.srand(1234); - - print("Starting getNear test: " + name); }; GeoNearRandomTest.prototype.mkPt = function mkPt(scale, indexBounds) { @@ -26,7 +28,7 @@ GeoNearRandomTest.prototype.mkPt = function mkPt(scale, indexBounds) { } }; -GeoNearRandomTest.prototype.insertPts = function(nPts, indexBounds, scale) { +GeoNearRandomTest.prototype.insertPts = function(nPts, indexBounds, scale, skipIndex) { assert.eq(this.nPts, 0, "insertPoints already called"); this.nPts = nPts; @@ -36,10 +38,12 @@ GeoNearRandomTest.prototype.insertPts = function(nPts, indexBounds, scale) { } assert.commandWorked(bulk.execute()); - if (!indexBounds) - this.t.ensureIndex({loc: '2d'}); - else - this.t.ensureIndex({loc: '2d'}, indexBounds); + if (!skipIndex) { + if (!indexBounds) + this.t.ensureIndex({loc: '2d'}); + else + this.t.ensureIndex({loc: '2d'}, indexBounds); + } }; GeoNearRandomTest.prototype.assertIsPrefix = function(short, long, errmsg) { diff --git a/src/mongo/db/geo/hash.cpp b/src/mongo/db/geo/hash.cpp index 41c6801bf63..c1170efd57e 100644 --- a/src/mongo/db/geo/hash.cpp +++ b/src/mongo/db/geo/hash.cpp @@ -687,21 +687,30 @@ Status GeoHashConverter::parseParameters(const BSONObj& paramDoc, << "but " << params->bits << " bits were specified"); } - if (params->min >= params->max) { + const bool rangeValid = params->min < params->max; + if (!rangeValid || std::isinf(params->min) || std::isinf(params->max)) { return Status(ErrorCodes::InvalidOptions, str::stream() << "region for hash must be valid and have positive area, " << "but [" << params->min << ", " << params->max << "] " << "was specified"); } - double numBuckets = (1024 * 1024 * 1024 * 4.0); + constexpr double numBuckets = 4.0 * 1024 * 1024 * 1024; params->scaling = numBuckets / (params->max - params->min); + const bool scalingValid = params->scaling > 0; + if (!scalingValid || std::isinf(params->scaling)) { + return Status(ErrorCodes::InvalidOptions, + str::stream() + << "range [" << params->min << ", " << params->max << "] is too small."); + } return Status::OK(); } GeoHashConverter::GeoHashConverter(const Parameters& params) : _params(params) { init(); + uassert( + 4799400, "Invalid GeoHashConverter parameters", _params.max - _params.min >= _error / 2); } void GeoHashConverter::init() { |