WMI server process leak using refreshers
Hi,
We found a memory leak problem in WMI while refreshing some high
performance data in remote systems with Windows Vista or Windows Server 2008
from a Windows XP system.
We made a test program based on your example in Accessing Performance Data
in C++ http://msdn2.microsoft.com/en-us/library/aa384724(VS.85).aspx to show
the memory use of the WMI remote service, the code of that program is
included below on this post.
The main difference with the official example is related about the
security used to connect to a remote system, because the example didn't work
for us while trying to monitor a remote machine. Other difference is that we
do not get the objects refreshed, we only call the Refresh() method. The last
difference is that we have two loops, one only for refreshes and one for the
full process to emulate some different scenarios
When we try to do only refreshes, the Commit Size value of the remote WMI
server process starts to grow slowly until all the refreshes are done, then
the server process dissapears abruptly after a while.
When we try to loop the full process, then the Commit Size of the server
process grows very fast, reaching hundredths of MB in seconds and then, when
the process in near 512 MB, the test application starts to receive the error
0x80004005 (Unspecified error) for each single operation. Some time later,
the error changes to 0x8007046a (Not enough server storage is available to
process this command.), 0x80041006 (There was not enough memory for the
operation) or 0x800700a4 (No more threads can be created in the system) for
every operation until the application ends.
If I run the same tests targetting a Windows XP system, the WMI server
process doesn't show any increase in the Commit Size.
Regards,
Tango
The test code is the following, need to replace the values of the user,
password and remote namespace in order to work
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <Wbemidl.h>
# pragma comment(lib, "wbemuuid.lib")
#define NUMBER_OF_REFRESHES 1
#define NUMBER_OF_FULL_LOOPS 1
#define NAME_SPACE L"\\\\Remote_System\\root\\cimv2"
#define DOMAIN L"Domain"
#define USER L"User"
#define FULL_USER L"Domain\\User"
#define PASSWORD L"Password"
int __cdecl wmain(int argc, wchar_t* argv[])
{
HRESULT hr = S_OK;
IWbemRefresher *pRefresher = NULL;
IWbemConfigureRefresher *pConfig = NULL;
IWbemHiPerfEnum *pEnum = NULL;
IWbemServices *pNameSpace = NULL;
IWbemLocator *pWbemLocator = NULL;
IUnknown *pUnkServ = NULL;
SEC_WINNT_AUTH_IDENTITY_W *pAuthIdentity = NULL;
BSTR bstrNameSpace = NULL;
BSTR bstrUserName = NULL;
BSTR userbstr = NULL;
BSTR domainbstr = NULL;
BSTR bstrPassword = NULL;
long lID = 0;
long lVirtualBytesHandle = 0;
long lIDProcessHandle = 0;
DWORD dwVirtualBytes = 0;
DWORD dwProcessId = 0;
DWORD dwNumObjects = 0;
DWORD dwNumReturned = 0;
DWORD dwIDProcess = 0;
DWORD i=0;
int x=0;
int y=0;
for(y = 0; y < NUMBER_OF_FULL_LOOPS; y++)
{
hr = S_OK;
pRefresher = NULL;
pConfig = NULL;
pEnum = NULL;
pNameSpace = NULL;
pWbemLocator = NULL;
pUnkServ = NULL;
pAuthIdentity = NULL;
bstrNameSpace = NULL;
bstrUserName = NULL;
userbstr = NULL;
domainbstr = NULL;
bstrPassword = NULL;
lID = 0;
lVirtualBytesHandle = 0;
lIDProcessHandle = 0;
dwVirtualBytes = 0;
dwProcessId = 0;
dwNumObjects = 0;
dwNumReturned = 0;
dwIDProcess = 0;
i=0;
if (FAILED (hr = CoInitializeEx(NULL,COINIT_MULTITHREADED)))
{
goto CLEANUP;
}
if (FAILED (hr = CoCreateInstance(
CLSID_WbemLocator,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
(void**) &pWbemLocator)))
{
goto CLEANUP;
}
// Connect to the desired namespace.
bstrNameSpace = SysAllocString(NAME_SPACE);
if (NULL == bstrNameSpace)
{
hr = E_OUTOFMEMORY;
goto CLEANUP;
}
userbstr = SysAllocString(USER);
if (NULL == userbstr)
{
hr = E_OUTOFMEMORY;
goto CLEANUP;
}
domainbstr = SysAllocString(DOMAIN);
if (NULL == domainbstr)
{
hr = E_OUTOFMEMORY;
goto CLEANUP;
}
bstrUserName = SysAllocString(FULL_USER);
if (NULL == bstrUserName)
{
hr = E_OUTOFMEMORY;
goto CLEANUP;
}
bstrPassword = SysAllocString(PASSWORD);
if (NULL == bstrPassword)
{
hr = E_OUTOFMEMORY;
goto CLEANUP;
}
if (FAILED (hr = pWbemLocator->ConnectServer(
bstrNameSpace,
bstrUserName, // User name
bstrPassword, // Password
NULL, // Locale
0L, // Security flags
NULL, // Authority
NULL, // Wbem context
&pNameSpace)))
{
goto CLEANUP;
}
pWbemLocator->Release();
pWbemLocator=NULL;
SysFreeString(bstrNameSpace);
bstrNameSpace = NULL;
SysFreeString(bstrUserName);
bstrUserName = NULL;
pAuthIdentity = new SEC_WINNT_AUTH_IDENTITY_W;
SecureZeroMemory(pAuthIdentity, sizeof(*pAuthIdentity));
pAuthIdentity->User = new WCHAR[100];
wcscpy (pAuthIdentity->User , userbstr);
pAuthIdentity->UserLength = wcslen(pAuthIdentity->User);
SysFreeString(userbstr);
userbstr = NULL;
pAuthIdentity->Domain = new WCHAR[100];
wcscpy(pAuthIdentity->Domain, domainbstr);
pAuthIdentity->DomainLength = wcslen(pAuthIdentity->Domain);
SysFreeString(domainbstr);
domainbstr = NULL;
pAuthIdentity->Password = new WCHAR[wcslen(bstrPassword)+1];;
wcscpy(pAuthIdentity->Password, bstrPassword);
pAuthIdentity->PasswordLength = wcslen(pAuthIdentity->Password);
SysFreeString(bstrPassword);
bstrPassword = NULL;
pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
if (FAILED (hr = CoSetProxyBlanket(pNameSpace,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
pAuthIdentity,
EOAC_NONE)))
{
goto CLEANUP;
}
if (FAILED (hr = pNameSpace->QueryInterface(IID_IUnknown, (void**)
&pUnkServ)))
{
goto CLEANUP;
}
if (FAILED (hr = CoSetProxyBlanket(pUnkServ,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
pAuthIdentity,
EOAC_NONE)))
{
goto CLEANUP;
}
if (FAILED (hr = CoCreateInstance(
CLSID_WbemRefresher,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWbemRefresher,
(void**) &pRefresher)))
{
goto CLEANUP;
}
if (FAILED (hr = pRefresher->QueryInterface(
IID_IWbemConfigureRefresher,
(void **)&pConfig)))
{
goto CLEANUP;
}
// Add an enumerator to the refresher.
if (FAILED (hr = pConfig->AddEnum(
pNameSpace,
L"Win32_PerfRawData_PerfProc_Process",
0,
NULL,
&pEnum,
&lID)))
{
goto CLEANUP;
}
pConfig->Release();
pConfig = NULL;
//Refresher loop
for(x = 0; x < NUMBER_OF_REFRESHES; x++)
{
if (FAILED (hr =pRefresher->Refresh(0L)))
{
goto CLEANUP;
}
}
// exit loop here
CLEANUP:
if (NULL != bstrNameSpace)
{
SysFreeString(bstrNameSpace);
bstrNameSpace = NULL;
}
if (NULL != bstrUserName)
{
SysFreeString(bstrUserName);
bstrUserName = NULL;
}
if (NULL != userbstr)
{
SysFreeString(userbstr);
userbstr = NULL;
}
if (NULL != domainbstr)
{
SysFreeString(domainbstr);
domainbstr = NULL;
}
if (NULL != bstrPassword)
{
SysFreeString(bstrPassword);
bstrPassword = NULL;
}
if (NULL != pWbemLocator)
{
pWbemLocator->Release();
}
if (NULL != pNameSpace)
{
pNameSpace->Release();
}
if (NULL != pUnkServ)
{
pUnkServ->Release();
}
if (NULL != pAuthIdentity)
{
if (NULL != pAuthIdentity->User)
delete [] pAuthIdentity->User;
pAuthIdentity->User = NULL;
if (NULL != pAuthIdentity->Domain)
delete [] pAuthIdentity->Domain;
pAuthIdentity->Domain = NULL;
if (NULL != pAuthIdentity->Password)
delete [] pAuthIdentity->Password;
pAuthIdentity->Password = NULL;
}
if (NULL != pEnum)
{
pEnum->Release();
}
if (NULL != pConfig)
{
pConfig->Release();
}
if (NULL != pRefresher)
{
pRefresher->Release();
}
CoUninitialize();
if (FAILED (hr))
{
wprintf (L"Error status=%08x\n",hr);
}
}
wprintf (L"End");
Sleep(600000);
return 1;
}
date: Fri, 11 Apr 2008 04:21:00 -0700
author: Tango am