mongo/jstests/aggregation/agg_infinite_recursion.js

72 lines
2.5 KiB
JavaScript

// This test checks that an infinite recursion correctly produces an 'InternalError: too much
// recursion' error and does not crash the server.
// @tags: [
// requires_scripting,
// ]
const makeBinData = () => BinData(4, "gf1UcxdHTJ2HQ/EGQrO7mQ==");
const makeUUID = () => UUID("81fd5473-1747-4c9d-8743-f10642b3bb99");
const makeHexData = () => new HexData(4, "81fd547317474c9d8743f10642b3bb99");
/* eslint-disable */
function whereFnTemplate() {
let testRecursiveFn = (i) => {
(__fn_placeholder__)();
testRecursiveFn(i + 1);
};
testRecursiveFn(0);
}
/* eslint-enable */
function recursiveFindWhere(db, collectionName, fn) {
return db[collectionName].runCommand("find", {
filter: {$where: whereFnTemplate.toString().replace("__fn_placeholder__", fn.toString())}
});
}
function recursiveAggregateFunction(db, collectionName, fn) {
return db.runCommand({
"aggregate": collectionName,
"pipeline": [{
$addFields: {
fld: {
$function: {
body:
whereFnTemplate.toString().replace("__fn_placeholder__", fn.toString()),
args: ["$name"],
lang: "js"
}
}
}
}],
cursor: {}
});
}
function assertThrowsInfiniteRecursion(res) {
assert.commandFailedWithCode(res, ErrorCodes.JSInterpreterFailure);
assert(/too much recursion/.test(res.errmsg),
`Error wasn't caused by infinite recursion: ${tojson(res)}`);
// The choice of 20 for the number of frames is somewhat arbitrary. We check for there to be
// some reasonable number of stack frames because most regressions would cause the stack to
// contain a single frame or none at all.
const kMinExpectedStack = 20;
assert.gte(res.errmsg.split("\n").length,
kMinExpectedStack,
`Error didn't preserve the JavaScript stacktrace: ${tojson(res)}`);
}
function runTests(db, collectionName, recursiveFn) {
assertThrowsInfiniteRecursion(recursiveFn(db, collectionName, makeBinData));
assertThrowsInfiniteRecursion(recursiveFn(db, collectionName, makeUUID));
assertThrowsInfiniteRecursion(recursiveFn(db, collectionName, makeHexData));
}
const collectionName = 'agg_infinite_recursion';
const collection = db[collectionName];
collection.drop();
assert.commandWorked(collection.insert({name: "Mo"}));
runTests(db, collectionName, recursiveFindWhere);
runTests(db, collectionName, recursiveAggregateFunction);