-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
Query Execution
-
ALL
-
0
-
None
-
None
-
None
-
None
-
None
-
None
-
None
Summary
The GranularityRounder helpers (granularity_rounder_powers_of_two.cpp and granularity_rounder_preferred_numbers.cpp) do not reject non-finite (infinity) numeric input. When a user pipeline feeds Infinity into $bucketAuto with a granularity (e.g. POWERSOF2), execution reaches representAsChecked<int>(...) with a non-finite double, which trips a tassert (BF-44396).
Reproducer
db.fuzzer_coll.aggregate([
{$sort: {_id: 1}},
{$bucketAuto: {
groupBy: {$trunc: {$numberDouble: "Infinity"}},
buckets: 12,
output: {num: {$max: {$bitOr: [1611, 46718, 89496]}}},
granularity: "POWERSOF2"
}}
])
Stack
representAsChecked<int,double> represent_as_util.h:43 GranularityRounderPowersOfTwo::roundDown granularity_rounder_powers_of_two.cpp:99 DocumentSourceBucketAuto::populateNextBucket document_source_bucket_auto.cpp:320 DocumentSourceBucketAuto::doGetNext document_source_bucket_auto.cpp:111
Tripwire: code 12961701 ("cannot represent value as target type").
Root cause
uassertNonNegativeNumber() in both granularity rounder files rejects non-numeric, NaN, and negative values, but not Infinity. Downstream, std::log2(Inf) = Inf, std::ceil(Inf) - 1 = Inf, and then representAsChecked<int>(Inf) fails. (Note: a plain static_cast<int>(Inf) is undefined behavior in C+ — the whole point of representAsChecked is to catch this.)
Fix
Extend uassertNonNegativeNumber in both files to also assert std::isfinite(number), converting this into a user-facing uassert with a clear message ("A granularity rounder cannot round infinity").
Affected branches
The missing infinity guard is old code, so v7.0, v8.0, v8.2, v8.3, and master all have the latent hole.
Related
BF-44396