Issue Status as of May 28, 2014
ISSUE SUMMARY
The query depth limit of 100 is not applied to deeply nested $not queries. For example:
db.coll.find({a: {$not: {$not: {$not: ... {$gt: 3} ... }}}})
USER IMPACT
Deeply nested $not queries crash mongod due to excessive recursion.
WORKAROUNDS
Rewrite the query to avoid excessive recursion.
AFFECTED VERSIONS
MongoDB production releases 2.6.0 and 2.6.1 are affected by this issue.
FIX VERSION
The fix is included in the 2.6.2 production release.
RESOLUTION DETAILS
The query depth limit of 100 now applies to $not trees.
Original description
The query depth limit of 100 (from SERVER-13661) is not applied to deeply nested $not queries. This leads to stack overflows due to excessive recursion.
Partial backtrace:
frame #0: 0x00000001002dd1b9 mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseNot(char const*, mongo::BSONElement const&) + 439 frame #1: 0x00000001002d4f3a mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSubField(mongo::BSONObj const&, mongo::AndMatchExpression const*, char const*, mongo::BSONElement const&) + 338 frame #2: 0x00000001002d85b4 mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSub(char const*, mongo::BSONObj const&, mongo::AndMatchExpression*) + 656 frame #3: 0x00000001002dd26d mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseNot(char const*, mongo::BSONElement const&) + 619 frame #4: 0x00000001002d4f3a mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSubField(mongo::BSONObj const&, mongo::AndMatchExpression const*, char const*, mongo::BSONElement const&) + 338 frame #5: 0x00000001002d85b4 mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSub(char const*, mongo::BSONObj const&, mongo::AndMatchExpression*) + 656 frame #6: 0x00000001002dd26d mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseNot(char const*, mongo::BSONElement const&) + 619 frame #7: 0x00000001002d4f3a mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSubField(mongo::BSONObj const&, mongo::AndMatchExpression const*, char const*, mongo::BSONElement const&) + 338 frame #8: 0x00000001002d85b4 mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSub(char const*, mongo::BSONObj const&, mongo::AndMatchExpression*) + 656 frame #9: 0x00000001002dd26d mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseNot(char const*, mongo::BSONElement const&) + 619 frame #10: 0x00000001002d4f3a mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSubField(mongo::BSONObj const&, mongo::AndMatchExpression const*, char const*, mongo::BSONElement const&) + 338 frame #11: 0x00000001002d85b4 mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSub(char const*, mongo::BSONObj const&, mongo::AndMatchExpression*) + 656 ... frame #1544: 0x00000001002d85b4 mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parseSub(char const*, mongo::BSONObj const&, mongo::AndMatchExpression*) + 656 frame #1545: 0x00000001002d9743 mongod-2.6.1-rc0`mongo::MatchExpressionParser::_parse(mongo::BSONObj const&, int) + 4125 frame #1546: 0x00000001003ae465 mongod-2.6.1-rc0`mongo::CanonicalQuery::canonicalize(mongo::QueryMessage const&, mongo::CanonicalQuery**) + 85 frame #1547: 0x00000001003d0525 mongod-2.6.1-rc0`mongo::newRunQuery(mongo::Message&, mongo::QueryMessage&, mongo::CurOp&, mongo::Message&) + 2725 frame #1548: 0x00000001002a14a0 mongod-2.6.1-rc0`mongo::assembleResponse(mongo::Message&, mongo::DbResponse&, mongo::HostAndPort const&) + 1968 frame #1549: 0x0000000100006ca4 mongod-2.6.1-rc0`mongo::MyMessageHandler::process(mongo::Message&, mongo::AbstractMessagingPort*, mongo::LastError*) + 308 frame #1550: 0x0000000100671c51 mongod-2.6.1-rc0`mongo::PortMessageServer::handleIncomingMsg(void*) + 1681 frame #1551: 0x00000001006e0c95 mongod-2.6.1-rc0`thread_proxy + 229 frame #1552: 0x00007fff93d8b772 libsystem_c.dylib`_pthread_start + 327 frame #1553: 0x00007fff93d781a1 libsystem_c.dylib`thread_start + 13