[SERVER-31305] Memory leak in QueryPlanner::plan due to unmanaged raw pointers Created: 28/Sep/17  Updated: 30/Oct/23  Resolved: 04/Oct/17

Status: Closed
Project: Core Server
Component/s: Querying
Affects Version/s: 3.5.13
Fix Version/s: 3.6.0-rc0

Type: Bug Priority: Major - P3
Reporter: Eddie Louie Assignee: Eddie Louie
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
Backwards Compatibility: Fully Compatible
Operating System: ALL
Steps To Reproduce:

The BF ticket has instructions on the ASAN builder needed to repro with
the following code changes.

--- a/src/mongo/db/query/query_planner.cpp
+++ b/src/mongo/db/query/query_planner.cpp
@@ -873,6 +873,8 @@ Status QueryPlanner::plan(const CanonicalQuery& query,
             // Store the plan cache index tree before calling prepareForAccessingPlanning(), so that
             // the PlanCacheIndexTree has the same sort as the MatchExpression used to generate the
             // plan cache key.
+            uassert(ErrorCodes::InternalError, "intentionally thrown", false);
+
             std::unique_ptr<MatchExpression> clone(rawTree->shallowClone());
             PlanCacheIndexTree* cacheData;
             Status indexTreeStatus =

And then running this script.

repro_bf6473.js

(function() {
    "use strict";
 
    assert.commandWorked(db.mycoll.createIndex({a: 1}));
    assert.commandWorked(db.mycoll.createIndex({b: 1}));
    assert.writeOK(db.mycoll.insert({}));
 
    var cursor = db.mycoll.find({a: 1, b: 2});
    cursor.hasNext();
})();

Sprint: TIG 2017-10-23
Participants:
Linked BF Score: 0

 Description   

In the QueryPlanner::plan function, a MatchExpression* rawTree pointer is assigned an object, but before it is able to pass off ownership to a smart pointer, an exception occurs. This leads to the memory being leaked.



 Comments   
Comment by Githook User [ 04/Oct/17 ]

Author:

{'email': 'eddie.louie@mongodb.com', 'name': 'Eddie Louie', 'username': 'elouie99'}

Message: SERVER-31305 Use smart pointer to prevent memory leak in
QueryPlanner::plan()
Branch: master
https://github.com/mongodb/mongo/commit/e329bd234dc00535b36a47ae998cf24a40552968

Comment by Eddie Louie [ 28/Sep/17 ]

src/mongo/db/query/query_planner.cpp

855
        MatchExpression* rawTree;
856
        while (isp.getNext(&rawTree) && (out->size() < params.maxIndexedSolutions)) {
857
            LOG(5) << "About to build solntree from tagged tree:" << endl
858
                   << redact(rawTree->toString());
859
 
860
            // Store the plan cache index tree before calling prepareForAccessingPlanning(), so that
861
            // the PlanCacheIndexTree has the same sort as the MatchExpression used to generate the
862
            // plan cache key.
863
            std::unique_ptr<MatchExpression> clone(rawTree->shallowClone());
864
            PlanCacheIndexTree* cacheData;
865
            Status indexTreeStatus =
866
                cacheDataFromTaggedTree(clone.get(), relevantIndices, &cacheData);
867
            if (!indexTreeStatus.isOK()) {
868
                LOG(5) << "Query is not cachable: " << redact(indexTreeStatus.reason());
869
            }
870
            unique_ptr<PlanCacheIndexTree> autoData(cacheData);
871
 
872
            // We have already cached the tree in canonical order, so now we can order the nodes for
873
            // access planning.
874
            prepareForAccessPlanning(rawTree);
875
 
876
            // This can fail if enumeration makes a mistake.
877
            std::unique_ptr<QuerySolutionNode> solnRoot(QueryPlannerAccess::buildIndexedDataAccess(
878
                query, rawTree, false, relevantIndices, params));

The object is assigned to rawTree from isp->getNext(), and an exception can be thrown from rawTree->shallowClone() at which point the rawTree object is leaked.

Here is an example of the actual mongod log message:

[MongoDFixture:job0] 2017-09-25T18:41:54.552+0000 D -        [conn14] User Assertion: 10209:name has to be a string: _id: ObjectId('59c94deda2875d6f04ad528d') src/mongo/db/matcher/expression_where.cpp 117
[MongoDFixture:job0] 2017-09-25T18:41:54.552+0000 W -        [conn14] DBException thrown :: caused by :: Location10209: name has to be a string: _id: ObjectId('59c94deda2875d6f04ad528d')
[MongoDFixture:job0] 2017-09-25T18:41:54.570+0000 I -        [conn14]
...
[MongoDFixture:job0]  mongod(__interceptor_backtrace+0x61) [0x5586a75b6451]
[MongoDFixture:job0]  mongod(_ZN5mongo15printStackTraceERSo+0x120) [0x5586abb4bc10]
[MongoDFixture:job0]  mongod(_ZN5mongo15printStackTraceEv+0x154) [0x5586abb4b9c4]
[MongoDFixture:job0]  mongod(_ZN5mongo11DBException13traceIfNeededERKS0_+0x3F4) [0x5586abb2bc84]
[MongoDFixture:job0]  mongod(_ZN5mongo11DBExceptionC2ERKNS_6StatusE+0x83) [0x5586a76650b3]
[MongoDFixture:job0]  mongod(_ZN5mongo11DBExceptionC2EiNS_10StringDataE+0xC4) [0x5586a76646e4]
[MongoDFixture:job0]  mongod(_ZN5mongo18AssertionExceptionC2EiNS_10StringDataE+0xE) [0x5586a82c5c6e]
[MongoDFixture:job0]  mongod(_ZN5mongo21uassertedWithLocationEiNS_10StringDataEPKcj+0x7AC) [0x5586abb3081c]
[MongoDFixture:job0]  mongod(_ZNK5mongo20WhereMatchExpression12shallowCloneEv+0x6EE) [0x5586a86a8c0e]
[MongoDFixture:job0]  mongod(_ZNK5mongo18AndMatchExpression12shallowCloneEv+0x20A) [0x5586ab2f81ea]
[MongoDFixture:job0]  mongod(_ZN5mongo18QueryPlannerAccess18makeCollectionScanERKNS_14CanonicalQueryEbRKNS_18QueryPlannerParamsE+0x169) [0x5586ab188c29]
[MongoDFixture:job0]  mongod(_ZN5mongo17buildCollscanSolnERKNS_14CanonicalQueryEbRKNS_18QueryPlannerParamsE+0xBB) [0x5586ab1ba8db]
[MongoDFixture:job0]  mongod(_ZN5mongo12QueryPlanner4planERKNS_14CanonicalQueryERKNS_18QueryPlannerParamsEPSt6vectorIPNS_13QuerySolutionESaIS9_EE+0x990E) [0x5586ab1cb72e]
[MongoDFixture:job0]  mongod(+0x231D134) [0x5586a863d134]
[MongoDFixture:job0]  mongod(_ZN5mongo16getExecutorCountEPNS_16OperationContextEPNS_10CollectionERKNS_12CountRequestEbNS_12PlanExecutor11YieldPolicyE+0x1076) [0x5586a864ee16]
[MongoDFixture:job0]  mongod(+0x19ABBD2) [0x5586a7ccbbd2]
[MongoDFixture:job0]  mongod(_ZN5mongo12BasicCommand11enhancedRunEPNS_16OperationContextERKNS_12OpMsgRequestERNS_14BSONObjBuilderE+0x29E) [0x5586aadab75e]
[MongoDFixture:job0]  mongod(_ZN5mongo7Command9publicRunEPNS_16OperationContextERKNS_12OpMsgRequestERNS_14BSONObjBuilderE+0x4A) [0x5586aada6c3a]
[MongoDFixture:job0]  mongod(+0x1964A08) [0x5586a7c84a08]
[MongoDFixture:job0]  mongod(_ZN5mongo23ServiceEntryPointMongod13handleRequestEPNS_16OperationContextERKNS_7MessageE+0x1A0D) [0x5586a7c7312d]
[MongoDFixture:job0]  mongod(_ZN5mongo19ServiceStateMachine15_processMessageERNS0_11ThreadGuardE+0x59A) [0x5586a7ca09da]
[MongoDFixture:job0]  mongod(_ZN5mongo19ServiceStateMachine15_runNextInGuardERNS0_11ThreadGuardE+0x402) [0x5586a7c9b402]
[MongoDFixture:job0]  mongod(_ZN5mongo19ServiceStateMachine7runNextEv+0xD7) [0x5586a7c9cde7]
[MongoDFixture:job0]  mongod(+0x197691A) [0x5586a7c9691a]
[MongoDFixture:job0]  mongod(+0x552D3C8) [0x5586ab84d3c8]
[MongoDFixture:job0]  libpthread.so.0(+0x76BA) [0x7f25ef0886ba]
[MongoDFixture:job0]  libc.so.6(clone+0x6D) [0x7f25eeba83dd]
[MongoDFixture:job0] -----  END BACKTRACE  -----

Generated at Thu Feb 08 04:26:37 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.