summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/core/geo_near_bounds_overflow.js49
-rw-r--r--jstests/libs/geo_near_random.js20
-rw-r--r--src/mongo/db/geo/hash.cpp13
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() {