CDatabase クラスで発生するメモリ リークの問題について

こんにちは、Visual Studio サポート チームです。

今回は、MFC の CDatabase クラスを特定の方法で使用した場合に発生するメモリ リークの問題についてご案内します。この現象は、Visual Studio 2012 以降のバージョンに含まれる MFC で発生します。

 

現象

CDatabase クラスの同一のオブジェクトに対して OpenEx メソッドと Close メソッドを使用するとメモリ リークが発生し、メモリ使用量が増加し続けます。

 

原因

この現象は Visual Studio 2012 で追加された、CDatabase クラスの接続文字列の暗号化を行う処理に起因しています。

OpenEx メソッドで接続文字列を暗号化するためのメモリが割り当てられますが、再度 OpenEx メソッドが呼び出された際にメモリを解放せず、新たに割り当てを行っていました。

なお、弊社ではこの問題を MFC の不具合と認識しており、Visual Studio の将来のバージョンで修正を検討しています。

弊社製品の不具合によりご迷惑をおかけし、大変申し訳ございません。

 

対処方法

以下のいずれかの方法により、メモリ リークの問題に対処することが可能です。

  1. 同一のオブジェクトに対して OpenEx メソッドを複数呼び出さないようにする。(OpenEx メソッドで割り当てたメモリはデストラクタで解放されます。)
  2. CDatabase クラスを継承し、OpenEx メソッドを修正する。

上記 2. の具体的な実装例を以下にご案内いたします。

 

<CDatabaseEx.h>

#pragma once#include <afxdb.h>class CDatabaseEx : public CDatabase{public:

CDatabaseEx();virtual ~CDatabaseEx();virtual BOOL OpenEx(LPCTSTR lpszConnectString, DWORD dwOptions = 0);

};

<CDatabase.cpp>

#include "stdafx.h"#include "DatabaseEx.h"CDatabaseEx::CDatabaseEx(){} CDatabaseEx::~CDatabaseEx(){} BOOL CDatabaseEx::OpenEx(LPCTSTR lpszConnectString, DWORD dwOptions){

ENSURE_VALID(this);ENSURE_ARG(lpszConnectString == nullptr || AfxIsValidString(lpszConnectString));ENSURE_ARG(!(dwOptions & noOdbcDialog && dwOptions & forceOdbcDialog));_ // Exclusive access not supported.ASSERT(!(dwOptions & openExclusive));m_bUpdatable = !(dwOptions & openReadOnly);_ TRY{

m_strConnect = lpszConnectString;DATA_BLOB connectBlob;connectBlob.pbData = (BYTE *)(m_strConnect.GetString());connectBlob.cbData = static_cast<DWORD>(AtlStrLen(m_strConnect) + 1) * sizeof(TCHAR);_ // START CDatabase クラスのメモリ リーク対応if (m_blobConnect.pbData != nullptr){

 LocalFree(m_blobConnect.pbData);m_blobConnect.pbData = nullptr; 

}// END   CDatabase クラスのメモリ リーク対応if (CryptProtectData(&connectBlob, nullptr, nullptr, nullptr, nullptr, 0, &m_blobConnect)){

SecureZeroMemory((BYTE *)(m_strConnect.GetString()), m_strConnect.GetLength() * sizeof(TCHAR));m_strConnect.Empty();

}// Allocate the HDBC and make connectionAllocConnect(dwOptions);if (!Connect(dwOptions))

return FALSE;

// Verify support for required functionality and cache infoVerifyConnect();GetConnectInfo();

}CATCH_ALL(e){

Free();THROW_LAST();

}END_CATCH_ALLreturn TRUE;

}

製品の不具合でご迷惑をおかけし誠に申し訳ありません。
上記対処策の他、Visual Studio 2017 をご利用の場合は修正のリリースをお待ちいただくこともご検討いただけましたら幸いです。