ISSUE SUMMARY
The server will leak memory when receiving a query with a $where expression inside an $elemMatch expression. Note that these queries are not valid and an error message will be correctly returned to the user. For example:
> db.foo.find({a:{$elemMatch:{$where:"1"}}}) error: { "$err" : "Can't canonicalize query: BadValue $elemMatch cannot contain $where expression", "code" : 17287 } >
USER IMPACT
Users may see increased memory consumption by mongod processes. In extreme circumstances with many such queries, the memory leak may lead mongod to consume too much memory and either crash or be killed by the operating system.
WORKAROUNDS
Fix the invalid query to remove either the $elemMatch operator or the $where operator.
AFFECTED VERSIONS
MongoDB production releases from 2.6.1 to 2.6.4 (inclusive) are affected by this issue.
FIX VERSION
The fix is included in the 2.6.5 production release.
RESOLUTION DETAILS
Fix memory leak in MatchExpressionParser::_parseElemMatch().
Original description
The above JS test will cause the server to leak memory (and eventually crash). The leak is reproducible in versions 2.6.1+ but not 2.6.0.
SERVER-13503 seems like the obvious culprit.
Valgrind output:
valgrind -q --leak-check=full --show-leak-kinds=definite --soname-synonyms=somalloc=NONE --suppressions=valgrind.suppressions --num-callers=35 ./mongod ==29826== 3,250 (800 direct, 2,450 indirect) bytes in 10 blocks are definitely lost in loss record 4,322 of 4,395 ==29826== at 0x4C2B2C0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==29826== by 0xA84311: mongo::WhereCallbackReal::parseWhere(mongo::BSONElement const&) const (expression_where.cpp:189) ==29826== by 0xA76739: mongo::MatchExpressionParser::_parse(mongo::BSONObj const&, int) (expression_parser.cpp:336) ==29826== by 0xA76ED7: mongo::MatchExpressionParser::_parseElemMatch(char const*, mongo::BSONElement const&, int) (expression_parser.cpp:699) ==29826== by 0xA78908: mongo::MatchExpressionParser::_parseSubField(mongo::BSONObj const&, mongo::AndMatchExpression const*, char const*, mongo::BSONElement const&, int) (expression_parser.cpp:262) ==29826== by 0xA75659: mongo::MatchExpressionParser::_parseSub(char const*, mongo::BSONObj const&, mongo::AndMatchExpression*, int) (expression_parser.cpp:456) ==29826== by 0xA76114: mongo::MatchExpressionParser::_parse(mongo::BSONObj const&, int) (expression_parser.cpp:376) ==29826== by 0xB3AE58: mongo::CanonicalQuery::canonicalize(mongo::QueryMessage const&, mongo::CanonicalQuery**, mongo::MatchExpressionParser::WhereCallback const&) (expression_parser.h:71) ==29826== by 0xB6564B: mongo::newRunQuery(mongo::OperationContext*, mongo::Message&, mongo::QueryMessage&, mongo::CurOp&, mongo::Message&) (new_find.cpp:499) ==29826== by 0xA4877D: mongo::assembleResponse(mongo::OperationContext*, mongo::Message&, mongo::DbResponse&, mongo::HostAndPort const&) (instance.cpp:263) ==29826== by 0x7D5C6B: mongo::MyMessageHandler::process(mongo::Message&, mongo::AbstractMessagingPort*, mongo::LastError*) (db.cpp:198) ==29826== by 0xE682E0: mongo::PortMessageServer::handleIncomingMsg(void*) (message_server_port.cpp:227) ==29826== by 0x4E3F181: start_thread (pthread_create.c:312) ==29826== by 0x5D7C38C: clone (clone.S:111)
- is related to
-
SERVER-13503 The $where operator should not be allowed under $elemMatch
- Closed
- related to
-
SERVER-16889 Query subsystem public API should use std::unique_ptr for ownership transfer
- Closed