mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
SERVER-60588 Don't attempt to coerce a double product to long
This commit is contained in:
parent
28c55c9701
commit
3df7340a53
@ -15,8 +15,7 @@ coll.drop();
|
||||
out.drop();
|
||||
|
||||
const nDocs = 50;
|
||||
// We seed the documents with large values for a. This enables the pipeline that exposes the
|
||||
// halloween problem to overflow and fail more quickly.
|
||||
// We seed the documents with large values for a.
|
||||
const largeNum = 1000 * 1000 * 1000;
|
||||
|
||||
// We set internalQueryExecYieldPeriodMS to 1 ms to have query execution yield as often as
|
||||
@ -32,7 +31,7 @@ assert.commandWorked(db.adminCommand({setParameter: 1, internalQueryExecYieldPer
|
||||
// multiple times.
|
||||
function insertDocuments(collObject) {
|
||||
const bulk = collObject.initializeUnorderedBulkOp();
|
||||
for (let i = 0; i < nDocs; i++) {
|
||||
for (let i = 1; i < nDocs; i++) {
|
||||
bulk.insert({_id: i, a: i * largeNum, largeArray: (new Array(1024 * 1024).join("a"))});
|
||||
}
|
||||
assert.commandWorked(bulk.execute());
|
||||
@ -57,25 +56,33 @@ function pipeline(outColl) {
|
||||
const differentCollPipeline = pipeline(out.getName());
|
||||
const sameCollPipeline = pipeline(coll.getName());
|
||||
|
||||
// Targeting a collection that is not the collection being agggregated over will result in each
|
||||
// Targeting a collection that is not the collection being aggregated over will result in each
|
||||
// document's value of 'a' being updated exactly once.
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: coll.getName(), pipeline: differentCollPipeline, cursor: {}}));
|
||||
|
||||
// Filter out 'largeArray' as we are only interested in verifying the value of "a" in each
|
||||
// document.
|
||||
const result = out.find({}, {largeArray: 0}).toArray();
|
||||
const diffCollResult = out.find({}, {largeArray: 0}).toArray();
|
||||
|
||||
for (const doc of result) {
|
||||
for (const doc of diffCollResult) {
|
||||
assert(doc.hasOwnProperty("a"), doc);
|
||||
const expectedVal = doc["_id"] * 2 * largeNum;
|
||||
assert.eq(doc["a"], expectedVal, doc);
|
||||
}
|
||||
|
||||
// Targeting the same collection that is being aggregated over will still result in each
|
||||
// document's value of 'a' being updated exactly once.
|
||||
assert.commandWorked(
|
||||
db.runCommand({aggregate: coll.getName(), pipeline: sameCollPipeline, cursor: {}}));
|
||||
|
||||
const sameCollResult = out.find({}, {largeArray: 0}).toArray();
|
||||
|
||||
for (const doc of sameCollResult) {
|
||||
assert(doc.hasOwnProperty("a"), doc);
|
||||
const expectedVal = doc["_id"] * 2 * largeNum;
|
||||
assert.eq(doc["a"], expectedVal, doc);
|
||||
}
|
||||
|
||||
// Because this pipeline writes to the collection being aggregated, it will cause documents to be
|
||||
// updated and pushed forward indefinitely. This will cause the computed values to eventually
|
||||
// overflow.
|
||||
assert.commandFailedWithCode(
|
||||
db.runCommand({aggregate: coll.getName(), pipeline: sameCollPipeline, cursor: {}}), 31109);
|
||||
MongoRunner.stopMongod(conn);
|
||||
}());
|
||||
|
@ -3120,11 +3120,15 @@ public:
|
||||
} else {
|
||||
doubleProduct *= val.coerceToDouble();
|
||||
|
||||
if (!std::isfinite(val.coerceToDouble()) ||
|
||||
overflow::mul(longProduct, val.coerceToLong(), &longProduct)) {
|
||||
// The number is either Infinity or NaN, or the 'longProduct' would have
|
||||
// overflowed, so we're abandoning it.
|
||||
productType = NumberDouble;
|
||||
if (productType != NumberDouble) {
|
||||
// If `productType` is not a double, it must be one of the integer types, so we
|
||||
// attempt to update `longProduct`.
|
||||
if (!std::isfinite(val.coerceToDouble()) ||
|
||||
overflow::mul(longProduct, val.coerceToLong(), &longProduct)) {
|
||||
// The multiplier is either Infinity or NaN, or the `longProduct` would
|
||||
// have overflowed, so we're abandoning it.
|
||||
productType = NumberDouble;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user