diff options
author | Alya Berciu <alyacarina@gmail.com> | 2021-05-21 15:24:08 +0100 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-05-25 13:58:09 +0000 |
commit | 8a16d9e587db35a2a9e21a0ec21ef07c47c7e2e5 (patch) | |
tree | 3132da2a2791cae9ca3de25b7729395643c8a259 | |
parent | 8b9eaa903128dea6c70093bddd8d2a241473ac24 (diff) | |
download | mongo-8a16d9e587db35a2a9e21a0ec21ef07c47c7e2e5.tar.gz |
SERVER-57091 Fix infinite loop in GranularityRounderPreferredNumbers::roundDown
(cherry picked from commit 441bef2c968ab24fe52d910c26dc3ecac366d0eb)
-rw-r--r-- | jstests/aggregation/sources/bucketauto/granularity_near_zero.js | 22 | ||||
-rw-r--r-- | src/mongo/db/pipeline/granularity_rounder_preferred_numbers.cpp | 7 |
2 files changed, 29 insertions, 0 deletions
diff --git a/jstests/aggregation/sources/bucketauto/granularity_near_zero.js b/jstests/aggregation/sources/bucketauto/granularity_near_zero.js new file mode 100644 index 00000000000..7f456f9428d --- /dev/null +++ b/jstests/aggregation/sources/bucketauto/granularity_near_zero.js @@ -0,0 +1,22 @@ +// Tests when the granularity rounder needs to approach zero to round correctly. This test was +// designed to reproduce SERVER-57091. +(function() { +"use strict"; +const coll = db.server57091; +coll.drop(); +coll.insertOne({}); + +const res = + coll.aggregate([{ + $bucketAuto: { + groupBy: { + $reduce: + {input: [], initialValue: 4.940656484124654e-324, in : {$size: ["$$value"]}} + }, + buckets: NumberLong("8"), + granularity: "R80" + } + }]) + .toArray(); +assert.eq(res, [{_id: {min: 0, max: 1.02e-321}, count: 1}]); +})(); diff --git a/src/mongo/db/pipeline/granularity_rounder_preferred_numbers.cpp b/src/mongo/db/pipeline/granularity_rounder_preferred_numbers.cpp index d99f640521c..efdcf46e432 100644 --- a/src/mongo/db/pipeline/granularity_rounder_preferred_numbers.cpp +++ b/src/mongo/db/pipeline/granularity_rounder_preferred_numbers.cpp @@ -306,6 +306,13 @@ Value GranularityRounderPreferredNumbers::roundDown(Value value) { multiplier /= 10.0; } + // It is possible to get a number so small that the resulting multiplier would have to be + // smaller than the precision of a double, in which case the multiplier would equal 0. In + // this case, we can round down to 0.0. + if (multiplier == 0) { + return Value(0.0); + } + double previousMax; while (number > (_baseSeries.back() * multiplier)) { previousMax = _baseSeries.back() * multiplier; |