From eac8d16add28e197df59bf5fbfd45fa39b9737f7 Mon Sep 17 00:00:00 2001 From: David Storch Date: Wed, 18 Mar 2015 15:24:09 -0400 Subject: [PATCH] SERVER-17282 fix use after free in the case of a database drop during a yield --- src/mongo/db/commands/find_cmd.cpp | 9 +++++++-- src/mongo/db/query/find.cpp | 11 ++++++----- src/mongo/db/query/find.h | 10 ++++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 277ea0fec87..156a10a897b 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -43,6 +43,7 @@ #include "mongo/db/query/explain.h" #include "mongo/db/query/find.h" #include "mongo/db/query/get_executor.h" +#include "mongo/db/server_parameters.h" #include "mongo/db/stats/counters.h" #include "mongo/s/d_state.h" #include "mongo/util/log.h" @@ -220,6 +221,9 @@ namespace mongo { AutoGetCollectionForRead ctx(txn, nss); Collection* collection = ctx.getCollection(); + const int dbProfilingLevel = ctx.getDb() ? ctx.getDb()->getProfilingLevel() : + serverGlobalParams.defaultProfile; + // 3) Get the execution plan for the query. // // TODO: Do we need to handle oplog replay here? @@ -251,7 +255,8 @@ namespace mongo { // there is no ClientCursor id, and then return. const int numResults = 0; const CursorId cursorId = 0; - endQueryOp(ctx, execHolder.get(), numResults, cursorId, txn->getCurOp()); + endQueryOp(execHolder.get(), dbProfilingLevel, numResults, cursorId, + txn->getCurOp()); Command::appendCursorResponseObject(cursorId, nss.ns(), BSONArray(), &result); return true; } @@ -333,7 +338,7 @@ namespace mongo { } // Fill out curop based on the results. - endQueryOp(ctx, exec, numResults, cursorId, txn->getCurOp()); + endQueryOp(exec, dbProfilingLevel, numResults, cursorId, txn->getCurOp()); // 7) Generate the response object to send to the client. Command::appendCursorResponseObject(cursorId, nss.ns(), firstBatch.arr(), &result); diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index f64f32d22af..bffdfae08bc 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -166,8 +166,8 @@ namespace mongo { curop->setQuery(queryObj); } - void endQueryOp(const AutoGetCollectionForRead& ctx, - PlanExecutor* exec, + void endQueryOp(PlanExecutor* exec, + int dbProfilingLevel, int numResults, CursorId cursorId, CurOp* curop) { @@ -186,8 +186,6 @@ namespace mongo { curop->debug().nscannedObjects = summaryStats.totalDocsExamined; curop->debug().idhack = summaryStats.isIdhack; - const int dbProfilingLevel = (ctx.getDb() != NULL) ? ctx.getDb()->getProfilingLevel() : - serverGlobalParams.defaultProfile; const logger::LogComponent queryLogComponent = logger::LogComponent::kQuery; const logger::LogSeverity logLevelOne = logger::LogSeverity::Debug(1); @@ -733,6 +731,9 @@ namespace mongo { AutoGetCollectionForRead ctx(txn, nss); Collection* collection = ctx.getCollection(); + const int dbProfilingLevel = ctx.getDb() ? ctx.getDb()->getProfilingLevel() : + serverGlobalParams.defaultProfile; + // We'll now try to get the query executor that will execute this query for us. There // are a few cases in which we know upfront which executor we should get and, therefore, // we shortcut the selection process here. @@ -896,7 +897,7 @@ namespace mongo { // Fill out curop based on query results. If we have a cursorid, we will fill out curop with // this cursorid later. long long ccId = 0; - endQueryOp(ctx, exec.get(), numResults, ccId, &curop); + endQueryOp(exec.get(), dbProfilingLevel, numResults, ccId, &curop); if (shouldSaveCursor(txn, collection, state, exec.get())) { // We won't use the executor until it's getMore'd. diff --git a/src/mongo/db/query/find.h b/src/mongo/db/query/find.h index c8511556928..2ab9e03b007 100644 --- a/src/mongo/db/query/find.h +++ b/src/mongo/db/query/find.h @@ -71,11 +71,13 @@ namespace mongo { /** * Fills out CurOp with information regarding this query's execution. * - * Uses explain functionality to extract stats from 'exec'. 'ctx' is used to conditionalize - * whether or not we do expensive stats gathering based on the database profiling level. + * Uses explain functionality to extract stats from 'exec'. + * + * The database profiling level, 'dbProfilingLevel', is used to conditionalize whether or not we + * do expensive stats gathering. */ - void endQueryOp(const AutoGetCollectionForRead& ctx, - PlanExecutor* exec, + void endQueryOp(PlanExecutor* exec, + int dbProfilingLevel, int numResults, CursorId cursorId, CurOp* curop);