Skip to content

Commit

Permalink
Merge #11043: Use std::unique_ptr (C++11) where possible
Browse files Browse the repository at this point in the history
a357293 Use MakeUnique<Db>(...) (practicalswift)
3e09b39 Use MakeUnique<T>(...) instead of std::unique_ptr<T>(new T(...)) (practicalswift)
8617989 Add MakeUnique (substitute for C++14 std::make_unique) (practicalswift)
d223bc9 Use unique_ptr for pcoinscatcher/pcoinsdbview/pcoinsTip/pblocktree (practicalswift)
b45c597 Use unique_ptr for pdbCopy (Db) and fix potential memory leak (practicalswift)
29ab96d Use unique_ptr for dbenv (DbEnv) (practicalswift)
f72cbf9 Use unique_ptr for pfilter (CBloomFilter) (practicalswift)
8ccf1bb Use unique_ptr for sem{Addnode,Outbound} (CSemaphore) (practicalswift)
73db063 Use unique_ptr for upnp_thread (boost::thread) (practicalswift)
0024531 Use unique_ptr for dbw (CDBWrapper) (practicalswift)
fa6d122 Use unique_ptr:s for {fee,short,long}Stats (TxConfirmStats) (practicalswift)
5a6f768 Use unique_ptr for httpRPCTimerInterface (HTTPRPCTimerInterface) (practicalswift)
860e912 Use unique_ptr for pwalletMain (CWallet) (practicalswift)

Pull request description:

  Use `std::unique_ptr` (C++11) where possible.

  Rationale:
  1. Avoid resource leaks (specifically: forgetting to `delete` an object created using `new`)
  2. Avoid undefined behaviour (specifically: double `delete`:s)

  **Note to reviewers:** Please let me know if I've missed any obvious `std::unique_ptr` candidates. Hopefully this PR should cover all the trivial cases.

Tree-SHA512: 9fbeb47b800ab8ff4e0be9f2a22ab63c23d5c613a0c6716d9183db8d22ddbbce592fb8384a8b7874bf7375c8161efb13ca2197ad6f24b75967148037f0f7b20c
  • Loading branch information
laanwj committed Nov 9, 2017
2 parents 23e9074 + a357293 commit 5e9be16
Show file tree
Hide file tree
Showing 20 changed files with 104 additions and 131 deletions.
11 changes: 5 additions & 6 deletions src/httprpc.cpp
Expand Up @@ -62,7 +62,7 @@ class HTTPRPCTimerInterface : public RPCTimerInterface
/* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
static HTTPRPCTimerInterface* httpRPCTimerInterface = nullptr;
static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;

static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
Expand Down Expand Up @@ -238,8 +238,8 @@ bool StartHTTPRPC()
RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC);
#endif
assert(EventBase());
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
RPCSetTimerInterface(httpRPCTimerInterface);
httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(EventBase());
RPCSetTimerInterface(httpRPCTimerInterface.get());
return true;
}

Expand All @@ -253,8 +253,7 @@ void StopHTTPRPC()
LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) {
RPCUnsetTimerInterface(httpRPCTimerInterface);
delete httpRPCTimerInterface;
httpRPCTimerInterface = nullptr;
RPCUnsetTimerInterface(httpRPCTimerInterface.get());
httpRPCTimerInterface.reset();
}
}
34 changes: 14 additions & 20 deletions src/init.cpp
Expand Up @@ -152,7 +152,7 @@ class CCoinsViewErrorCatcher final : public CCoinsViewBacked
// Writes do not need similar protection, as failure to write is handled by the caller.
};

static CCoinsViewErrorCatcher *pcoinscatcher = nullptr;
static std::unique_ptr<CCoinsViewErrorCatcher> pcoinscatcher;
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;

void Interrupt(boost::thread_group& threadGroup)
Expand Down Expand Up @@ -235,14 +235,10 @@ void Shutdown()
if (pcoinsTip != nullptr) {
FlushStateToDisk();
}
delete pcoinsTip;
pcoinsTip = nullptr;
delete pcoinscatcher;
pcoinscatcher = nullptr;
delete pcoinsdbview;
pcoinsdbview = nullptr;
delete pblocktree;
pblocktree = nullptr;
pcoinsTip.reset();
pcoinscatcher.reset();
pcoinsdbview.reset();
pblocktree.reset();
}
#ifdef ENABLE_WALLET
StopWallets();
Expand Down Expand Up @@ -1406,12 +1402,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
do {
try {
UnloadBlockIndex();
delete pcoinsTip;
delete pcoinsdbview;
delete pcoinscatcher;
delete pblocktree;

pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReset);
pcoinsTip.reset();
pcoinsdbview.reset();
pcoinscatcher.reset();
pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));

if (fReset) {
pblocktree->WriteReindexing(true);
Expand Down Expand Up @@ -1462,8 +1456,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// At this point we're either in reindex or we've loaded a useful
// block tree into mapBlockIndex!

pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState);
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState));
pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get()));

// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
Expand All @@ -1473,13 +1467,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}

// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!ReplayBlocks(chainparams, pcoinsdbview)) {
if (!ReplayBlocks(chainparams, pcoinsdbview.get())) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
break;
}

// The on-disk coinsdb is now in a good state, create the cache
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));

bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
if (!is_coinsview_empty) {
Expand Down Expand Up @@ -1521,7 +1515,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}

if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected");
break;
Expand Down
24 changes: 8 additions & 16 deletions src/net.cpp
Expand Up @@ -1534,22 +1534,20 @@ void ThreadMapPort()

void MapPort(bool fUseUPnP)
{
static boost::thread* upnp_thread = nullptr;
static std::unique_ptr<boost::thread> upnp_thread;

if (fUseUPnP)
{
if (upnp_thread) {
upnp_thread->interrupt();
upnp_thread->join();
delete upnp_thread;
}
upnp_thread = new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort));
upnp_thread.reset(new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)));
}
else if (upnp_thread) {
upnp_thread->interrupt();
upnp_thread->join();
delete upnp_thread;
upnp_thread = nullptr;
upnp_thread.reset();
}
}

Expand Down Expand Up @@ -2224,8 +2222,6 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe
nLastNodeId = 0;
nSendBufferMaxSize = 0;
nReceiveFloodSize = 0;
semOutbound = nullptr;
semAddnode = nullptr;
flagInterruptMsgProc = false;
SetTryNewOutboundPeer(false);

Expand Down Expand Up @@ -2331,11 +2327,11 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)

if (semOutbound == nullptr) {
// initialize semaphore
semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
semOutbound = MakeUnique<CSemaphore>(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
}
if (semAddnode == nullptr) {
// initialize semaphore
semAddnode = new CSemaphore(nMaxAddnode);
semAddnode = MakeUnique<CSemaphore>(nMaxAddnode);
}

//
Expand Down Expand Up @@ -2458,10 +2454,8 @@ void CConnman::Stop()
vNodes.clear();
vNodesDisconnected.clear();
vhListenSocket.clear();
delete semOutbound;
semOutbound = nullptr;
delete semAddnode;
semAddnode = nullptr;
semOutbound.reset();
semAddnode.reset();
}

void CConnman::DeleteNode(CNode* pnode)
Expand Down Expand Up @@ -2747,7 +2741,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nNextInvSend = 0;
fRelayTxes = false;
fSentAddr = false;
pfilter = new CBloomFilter();
pfilter = MakeUnique<CBloomFilter>();
timeLastMempoolReq = 0;
nLastBlockTime = 0;
nLastTXTime = 0;
Expand Down Expand Up @@ -2777,8 +2771,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
CNode::~CNode()
{
CloseSocket(hSocket);

delete pfilter;
}

void CNode::AskFor(const CInv& inv)
Expand Down
6 changes: 3 additions & 3 deletions src/net.h
Expand Up @@ -399,8 +399,8 @@ class CConnman
/** Services this instance offers */
ServiceFlags nLocalServices;

CSemaphore *semOutbound;
CSemaphore *semAddnode;
std::unique_ptr<CSemaphore> semOutbound;
std::unique_ptr<CSemaphore> semAddnode;
int nMaxConnections;
int nMaxOutbound;
int nMaxAddnode;
Expand Down Expand Up @@ -648,7 +648,7 @@ class CNode
bool fSentAddr;
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
CBloomFilter* pfilter;
std::unique_ptr<CBloomFilter> pfilter;
std::atomic<int> nRefCount;

const uint64_t nKeyedNetGroup;
Expand Down
10 changes: 4 additions & 6 deletions src/net_processing.cpp
Expand Up @@ -2102,7 +2102,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr

if (!AlreadyHave(inv) &&
AcceptToMemoryPool(mempool, state, ptx, &fMissingInputs, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
mempool.check(pcoinsTip);
mempool.check(pcoinsTip.get());
RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
vWorkQueue.emplace_back(inv.hash, i);
Expand Down Expand Up @@ -2169,7 +2169,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
recentRejects->insert(orphanHash);
}
}
mempool.check(pcoinsTip);
mempool.check(pcoinsTip.get());
}
}

Expand Down Expand Up @@ -2751,8 +2751,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
else
{
LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter.reset(new CBloomFilter(filter));
pfrom->pfilter->UpdateEmptyFull();
pfrom->fRelayTxes = true;
}
Expand Down Expand Up @@ -2788,8 +2787,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
{
LOCK(pfrom->cs_filter);
if (pfrom->GetLocalServices() & NODE_BLOOM) {
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter();
pfrom->pfilter.reset(new CBloomFilter());
}
pfrom->fRelayTxes = true;
}
Expand Down
24 changes: 9 additions & 15 deletions src/policy/fees.cpp
Expand Up @@ -548,16 +548,13 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
bucketMap[INF_FEERATE] = bucketIndex;
assert(bucketMap.size() == buckets.size());

feeStats = new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE);
shortStats = new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE);
longStats = new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE);
feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
}

CBlockPolicyEstimator::~CBlockPolicyEstimator()
{
delete feeStats;
delete shortStats;
delete longStats;
}

void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
Expand Down Expand Up @@ -690,16 +687,16 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
double sufficientTxs = SUFFICIENT_FEETXS;
switch (horizon) {
case FeeEstimateHorizon::SHORT_HALFLIFE: {
stats = shortStats;
stats = shortStats.get();
sufficientTxs = SUFFICIENT_TXS_SHORT;
break;
}
case FeeEstimateHorizon::MED_HALFLIFE: {
stats = feeStats;
stats = feeStats.get();
break;
}
case FeeEstimateHorizon::LONG_HALFLIFE: {
stats = longStats;
stats = longStats.get();
break;
}
default: {
Expand Down Expand Up @@ -1002,12 +999,9 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
}

// Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
delete feeStats;
delete shortStats;
delete longStats;
feeStats = fileFeeStats.release();
shortStats = fileShortStats.release();
longStats = fileLongStats.release();
feeStats = std::move(fileFeeStats);
shortStats = std::move(fileShortStats);
longStats = std::move(fileLongStats);

nBestSeenHeight = nFileBestSeenHeight;
historicalFirst = nFileHistoricalFirst;
Expand Down
6 changes: 3 additions & 3 deletions src/policy/fees.h
Expand Up @@ -245,9 +245,9 @@ class CBlockPolicyEstimator
std::map<uint256, TxStatsInfo> mapMemPoolTxs;

/** Classes to track historical data on transaction confirmations */
TxConfirmStats* feeStats;
TxConfirmStats* shortStats;
TxConfirmStats* longStats;
std::unique_ptr<TxConfirmStats> feeStats;
std::unique_ptr<TxConfirmStats> shortStats;
std::unique_ptr<TxConfirmStats> longStats;

unsigned int trackedTxs;
unsigned int untrackedTxs;
Expand Down
3 changes: 0 additions & 3 deletions src/qt/test/rpcnestedtests.h
Expand Up @@ -17,9 +17,6 @@ class RPCNestedTests : public QObject

private Q_SLOTS:
void rpcNestedTests();

private:
CCoinsViewDB *pcoinsdbview;
};

#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
6 changes: 3 additions & 3 deletions src/rpc/blockchain.cpp
Expand Up @@ -928,7 +928,7 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)

CCoinsStats stats;
FlushStateToDisk();
if (GetUTXOStats(pcoinsdbview, stats)) {
if (GetUTXOStats(pcoinsdbview.get(), stats)) {
ret.push_back(Pair("height", (int64_t)stats.nHeight));
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
Expand Down Expand Up @@ -996,7 +996,7 @@ UniValue gettxout(const JSONRPCRequest& request)
Coin coin;
if (fMempool) {
LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool);
CCoinsViewMemPool view(pcoinsTip.get(), mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
return NullUniValue;
}
Expand Down Expand Up @@ -1048,7 +1048,7 @@ UniValue verifychain(const JSONRPCRequest& request)
if (!request.params[1].isNull())
nCheckDepth = request.params[1].get_int();

return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);
return CVerifyDB().VerifyDB(Params(), pcoinsTip.get(), nCheckLevel, nCheckDepth);
}

/** Implementation of IsSuperMajority with better feedback */
Expand Down
10 changes: 4 additions & 6 deletions src/test/dbwrapper_tests.cpp
Expand Up @@ -125,7 +125,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
create_directories(ph);

// Set up a non-obfuscated wrapper to write some initial data.
CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = InsecureRand256();
uint256 res;
Expand All @@ -135,8 +135,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());

// Call the destructor to free leveldb LOCK
delete dbw;
dbw = nullptr;
dbw.reset();

// Now, set up another wrapper that wants to obfuscate the same directory
CDBWrapper odbw(ph, (1 << 10), false, false, true);
Expand Down Expand Up @@ -167,7 +166,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
create_directories(ph);

// Set up a non-obfuscated wrapper to write some initial data.
CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = InsecureRand256();
uint256 res;
Expand All @@ -177,8 +176,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());

// Call the destructor to free leveldb LOCK
delete dbw;
dbw = nullptr;
dbw.reset();

// Simulate a -reindex by wiping the existing data store
CDBWrapper odbw(ph, (1 << 10), false, true, true);
Expand Down

0 comments on commit 5e9be16

Please sign in to comment.