1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
// This test checks that an infinite recursion correctly produces an 'InternalError: too much
// recursion' error and does not crash the server.
(function() {
"use strict";
const makeBinData = () => BinData(4, "gf1UcxdHTJ2HQ/EGQrO7mQ==");
const makeUUID = () => UUID("81fd5473-1747-4c9d-8743-f10642b3bb99");
const makeHexData = () => new HexData(4, "81fd547317474c9d8743f10642b3bb99");
function whereFnTemplate() {
let testRecursiveFn = (i) => {
(__fn_placeholder__)();
testRecursiveFn(i + 1);
};
testRecursiveFn(0);
}
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);
})();
|