You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1337 lines
26 KiB
1337 lines
26 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: alloc.cpp
|
|
//
|
|
// Contents: Cert Server debug implementation
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "pch.cpp"
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <assert.h>
|
|
#include <psapi.h>
|
|
|
|
#define __dwFILE__ __dwFILE_CERTCLIB_ALLOC_CPP__
|
|
|
|
|
|
#if DBG_CERTSRV
|
|
|
|
#undef FormatMessageW
|
|
#undef LocalAlloc
|
|
#undef LocalReAlloc
|
|
#undef LocalFree
|
|
|
|
#undef CoTaskMemAlloc
|
|
#undef CoTaskMemRealloc
|
|
#undef CoTaskMemFree
|
|
|
|
#undef StringFromCLSID
|
|
#undef StringFromIID
|
|
|
|
#undef SysAllocString
|
|
#undef SysReAllocString
|
|
#undef SysAllocStringLen
|
|
#undef SysReAllocStringLen
|
|
#undef SysFreeString
|
|
#undef SysAllocStringByteLen
|
|
#undef PropVariantClear
|
|
#undef VariantClear
|
|
#undef VariantChangeType
|
|
#undef VariantChangeTypeEx
|
|
#undef AllocateAndInitializeSid
|
|
#undef FreeSid
|
|
|
|
#ifndef CSM_TRACEASSERT
|
|
#define CSM_TRACEASSERT 0x400
|
|
#endif
|
|
|
|
DWORD g_MemTrack = 0;
|
|
|
|
#define MTF_UNREGISTERED 0x00000002
|
|
#define MTF_ALLOCTRACE 0x00000004
|
|
#define MTF_FREETRACE 0x00000008
|
|
#define MTF_STACKTRACE 0x00000010
|
|
|
|
typedef struct _RMALLOC
|
|
{
|
|
LONG cAlloc;
|
|
LONG cAllocTotal;
|
|
} RMALLOC;
|
|
|
|
RMALLOC g_armAlloc[CSM_MAX];
|
|
|
|
#define C_BP_FRAME 16
|
|
#define C_BACK_TRACE_CHUNK 100
|
|
#define C_MEM_HEADER_CHUNK 100
|
|
|
|
typedef struct _BACKTRACE
|
|
{
|
|
LONG cAlloc; // count of outstanding allocations
|
|
LONG cAllocTotal; // count of total allocations
|
|
LONG cbAlloc; // size of outstanding allocations
|
|
LONG cbAllocTotal; // size of total allocations
|
|
ULONG apCaller[C_BP_FRAME]; // stack trace
|
|
} BACKTRACE;
|
|
|
|
typedef struct _MEMHEADER
|
|
{
|
|
DWORD iBackTrace; // backtrace index
|
|
VOID const *pvMemory; // Pointer to memory block allocated
|
|
LONG cbMemory; // Size of memory block allocated
|
|
DWORD Flags; // Allocator flags
|
|
} MEMHEADER;
|
|
|
|
WCHAR s_wszProcess[MAX_PATH];
|
|
|
|
|
|
// critical section around myRegister APIs since they
|
|
// operate on global data structures
|
|
CRITICAL_SECTION g_critsecRegisterMemory;
|
|
BOOL g_fRegisterMemoryCritSecInit = FALSE;
|
|
|
|
|
|
|
|
VOID
|
|
RegisterMemoryEnterCriticalSection(VOID)
|
|
{
|
|
HRESULT hr;
|
|
|
|
__try
|
|
{
|
|
if (!g_fRegisterMemoryCritSecInit)
|
|
{
|
|
InitializeCriticalSection(&g_critsecRegisterMemory);
|
|
g_fRegisterMemoryCritSecInit = TRUE;
|
|
}
|
|
EnterCriticalSection(&g_critsecRegisterMemory);
|
|
if (s_wszProcess[0] == L'\0')
|
|
{
|
|
GetModuleBaseName(
|
|
GetCurrentProcess(),
|
|
GetModuleHandle(NULL),
|
|
s_wszProcess,
|
|
ARRAYSIZE(s_wszProcess));
|
|
s_wszProcess[ARRAYSIZE(s_wszProcess) - 1] = L'\0';
|
|
if (s_wszProcess[0] == L'\0')
|
|
{
|
|
wcscpy(s_wszProcess, L"???");
|
|
}
|
|
|
|
}
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
RegisterMemoryLeaveCriticalSection(VOID)
|
|
{
|
|
if (g_fRegisterMemoryCritSecInit)
|
|
{
|
|
LeaveCriticalSection(&g_critsecRegisterMemory);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
RegisterMemoryDeleteCriticalSection()
|
|
{
|
|
if (g_fRegisterMemoryCritSecInit)
|
|
{
|
|
DeleteCriticalSection(&g_critsecRegisterMemory);
|
|
g_fRegisterMemoryCritSecInit = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BACKTRACE *g_rgbt = NULL;
|
|
DWORD g_cbtMax = 0;
|
|
DWORD g_cbt = 0;
|
|
|
|
MEMHEADER *g_rgmh = NULL;
|
|
DWORD g_cmhMax = 0;
|
|
DWORD g_cmh = 0;
|
|
|
|
|
|
MEMHEADER *
|
|
AllocMemHeader()
|
|
{
|
|
if (g_cmh >= g_cmhMax)
|
|
{
|
|
DWORD cb = (C_MEM_HEADER_CHUNK + g_cmhMax) * sizeof(g_rgmh[0]);
|
|
MEMHEADER *rgmhT;
|
|
|
|
if (NULL == g_rgmh)
|
|
{
|
|
rgmhT = (MEMHEADER *) LocalAlloc(LMEM_FIXED, cb);
|
|
}
|
|
else
|
|
{
|
|
rgmhT = (MEMHEADER *) LocalReAlloc(g_rgmh, cb, LMEM_MOVEABLE);
|
|
}
|
|
if (NULL == rgmhT)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"Error allocating memtrack header\n"));
|
|
return(NULL);
|
|
}
|
|
g_rgmh = rgmhT;
|
|
g_cmhMax += C_MEM_HEADER_CHUNK;
|
|
}
|
|
return(&g_rgmh[g_cmh++]);
|
|
}
|
|
|
|
|
|
MEMHEADER *
|
|
LookupMemHeader(
|
|
IN VOID const *pv)
|
|
{
|
|
MEMHEADER *pmh;
|
|
MEMHEADER *pmhEnd;
|
|
|
|
pmh = g_rgmh;
|
|
pmhEnd = &g_rgmh[g_cmh];
|
|
|
|
while (pmh < pmhEnd)
|
|
{
|
|
if (pv == pmh->pvMemory)
|
|
{
|
|
// Catch all activity on "interesting" blocks of memory.
|
|
// Ususally set in the debugger on a particular block of memory,
|
|
// to stop in the debugger when it is freed.
|
|
|
|
CSASSERT(0 == (CSM_TRACEASSERT & pmh->Flags));
|
|
return(pmh);
|
|
}
|
|
pmh++;
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeMemHeader(
|
|
IN MEMHEADER *pmh)
|
|
{
|
|
MEMHEADER *pmhLast;
|
|
|
|
assert(1 <= g_cmh);
|
|
pmhLast = &g_rgmh[g_cmh - 1];
|
|
|
|
*pmh = *pmhLast;
|
|
g_cmh--;
|
|
}
|
|
|
|
|
|
BACKTRACE *
|
|
AllocBackTrace(
|
|
OUT DWORD *pibt)
|
|
{
|
|
BOOL fRealloc = FALSE;
|
|
BACKTRACE *rgbtOld = g_rgbt;
|
|
BACKTRACE *pbtRet;
|
|
|
|
if (g_cbt >= g_cbtMax)
|
|
{
|
|
DWORD cb = (C_BACK_TRACE_CHUNK + g_cbtMax) * sizeof(g_rgbt[0]);
|
|
BACKTRACE *rgbtT;
|
|
|
|
if (NULL == g_rgbt)
|
|
{
|
|
rgbtT = (BACKTRACE *) LocalAlloc(LMEM_FIXED, cb);
|
|
}
|
|
else
|
|
{
|
|
rgbtT = (BACKTRACE *) LocalReAlloc(g_rgbt, cb, LMEM_MOVEABLE);
|
|
fRealloc = TRUE;
|
|
}
|
|
if (NULL == rgbtT)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"Error allocating memtrack backtrace\n"));
|
|
return(NULL);
|
|
}
|
|
g_rgbt = rgbtT;
|
|
g_cbtMax += C_BACK_TRACE_CHUNK;
|
|
}
|
|
*pibt = g_cbt + 1;
|
|
pbtRet = &g_rgbt[g_cbt++];
|
|
|
|
if (fRealloc)
|
|
{
|
|
// Wait to DBGPRINT here to avoid recursing with inconsistent data.
|
|
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIBI,
|
|
L"Realloc'd memtrack backtrace from %x to %x\n",
|
|
rgbtOld,
|
|
g_rgbt));
|
|
}
|
|
return(pbtRet);
|
|
}
|
|
|
|
|
|
BACKTRACE *
|
|
LookupBackTrace(
|
|
IN BACKTRACE *pbtIn,
|
|
OUT DWORD *pibt)
|
|
{
|
|
BACKTRACE *pbt;
|
|
BACKTRACE *pbtEnd;
|
|
|
|
pbt = g_rgbt;
|
|
pbtEnd = &g_rgbt[g_cbt];
|
|
|
|
while (pbt < pbtEnd)
|
|
{
|
|
if (0 == memcmp(pbt->apCaller, pbtIn->apCaller, sizeof(pbt->apCaller)))
|
|
{
|
|
*pibt = SAFE_SUBTRACT_POINTERS(pbt, g_rgbt) + 1;
|
|
return(pbt);
|
|
}
|
|
pbt++;
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
BACKTRACE *
|
|
BackTraceFromIndex(
|
|
IN DWORD ibt)
|
|
{
|
|
BACKTRACE *pbt = NULL;
|
|
|
|
if (0 == ibt)
|
|
{
|
|
DBGPRINTW((DBG_SS_CERTLIB, L"BackTraceFromIndex(0)\n"));
|
|
}
|
|
else if (g_cbt < ibt)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"BackTraceFromIndex(%u) -- out of range\n",
|
|
ibt));
|
|
}
|
|
else
|
|
{
|
|
pbt = &g_rgbt[ibt - 1];
|
|
}
|
|
return(pbt);
|
|
}
|
|
|
|
|
|
VOID
|
|
ReadEnvironmentFlags(VOID)
|
|
{
|
|
HRESULT hr;
|
|
DWORD MemTrack;
|
|
DWORD cb;
|
|
DWORD dwType;
|
|
HKEY hkey = NULL;
|
|
char *pszEnvVar;
|
|
|
|
pszEnvVar = getenv(szCERTSRV_MEMTRACK);
|
|
if (NULL != pszEnvVar)
|
|
{
|
|
g_MemTrack = (DWORD) strtol(pszEnvVar, NULL, 16);
|
|
}
|
|
else
|
|
{
|
|
hr = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
wszREGKEYCONFIGPATH,
|
|
0,
|
|
KEY_READ,
|
|
&hkey);
|
|
if (S_OK == hr)
|
|
{
|
|
cb = sizeof(MemTrack);
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
wszREGCERTSRVMEMTRACK,
|
|
0,
|
|
&dwType,
|
|
(BYTE *) &MemTrack,
|
|
&cb);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(MemTrack) == cb)
|
|
{
|
|
g_MemTrack = MemTrack;
|
|
}
|
|
}
|
|
}
|
|
|
|
//error:
|
|
if (NULL != hkey)
|
|
{
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CaptureStackBackTrace(
|
|
EXCEPTION_POINTERS *pep,
|
|
ULONG cSkip,
|
|
ULONG cFrames,
|
|
ULONG *aeip)
|
|
{
|
|
ZeroMemory(aeip, cFrames * sizeof(aeip[0]));
|
|
|
|
#if i386 == 1
|
|
ULONG ieip, *pebp;
|
|
ULONG *pebpMax = (ULONG *) MAXLONG; // 2 * 1024 * 1024 * 1024; // 2 gig - 1
|
|
ULONG *pebpMin = (ULONG *) (64 * 1024); // 64k
|
|
|
|
if (pep == NULL)
|
|
{
|
|
ieip = 0;
|
|
cSkip++; // always skip current frame
|
|
pebp = ((ULONG *) &pep) - 2;
|
|
}
|
|
else
|
|
{
|
|
ieip = 1;
|
|
assert(cSkip == 0);
|
|
aeip[0] = pep->ContextRecord->Eip;
|
|
pebp = (ULONG *) pep->ContextRecord->Ebp;
|
|
}
|
|
if (pebp >= pebpMin && pebp < pebpMax)
|
|
{
|
|
__try
|
|
{
|
|
for ( ; ieip < cSkip + cFrames; ieip++)
|
|
{
|
|
if (ieip >= cSkip)
|
|
{
|
|
aeip[ieip - cSkip] = *(pebp + 1); // save an eip
|
|
}
|
|
|
|
ULONG *pebpNext = (ULONG *) *pebp;
|
|
if (pebpNext < pebp + 2 ||
|
|
pebpNext >= pebpMax - 1 ||
|
|
pebpNext >= pebp + (256 * 1024) / sizeof(pebp[0]))
|
|
{
|
|
break;
|
|
}
|
|
pebp = pebpNext;
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
;
|
|
}
|
|
}
|
|
#endif // i386 == 1
|
|
}
|
|
|
|
|
|
WCHAR const *
|
|
wszAllocator(
|
|
IN DWORD Flags)
|
|
{
|
|
WCHAR const *pwsz;
|
|
|
|
switch (~CSM_TRACEASSERT & Flags)
|
|
{
|
|
case CSM_LOCALALLOC: pwsz = L"LocalAlloc"; break;
|
|
case CSM_COTASKALLOC: pwsz = L"CoTaskMemAlloc"; break;
|
|
case CSM_SYSALLOC: pwsz = L"SysAllocString"; break;
|
|
case CSM_MALLOC: pwsz = L"malloc"; break;
|
|
case CSM_NEW: pwsz = L"new"; break;
|
|
case CSM_NEW | CSM_GLOBALDESTRUCTOR:
|
|
pwsz = L"new-global"; break;
|
|
case CSM_SID: pwsz = L"allocSid"; break;
|
|
default: pwsz = L"???"; break;
|
|
}
|
|
return(pwsz);
|
|
}
|
|
|
|
|
|
WCHAR const *
|
|
wszFreeer(
|
|
IN DWORD Flags)
|
|
{
|
|
WCHAR const *pwsz;
|
|
|
|
switch (~CSM_TRACEASSERT & Flags)
|
|
{
|
|
case CSM_LOCALALLOC: pwsz = L"LocalFree"; break;
|
|
case CSM_COTASKALLOC: pwsz = L"CoTaskMemFree"; break;
|
|
case CSM_SYSALLOC: pwsz = L"SysFreeString"; break;
|
|
case CSM_MALLOC: pwsz = L"free"; break;
|
|
case CSM_NEW: pwsz = L"delete"; break;
|
|
case CSM_NEW | CSM_GLOBALDESTRUCTOR:
|
|
pwsz = L"delete-global"; break;
|
|
case CSM_SID: pwsz = L"FreeSid"; break;
|
|
default: pwsz = L"???"; break;
|
|
}
|
|
return(pwsz);
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpMemBlock(
|
|
IN WCHAR const *pwsz,
|
|
IN VOID const *pvMemory,
|
|
IN DWORD cbMemory,
|
|
IN DWORD Flags,
|
|
IN DWORD ibt,
|
|
OPTIONAL IN BACKTRACE const *pbt)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"%ws%wspv=%-6x cb=%-4x f=%x(%ws) pbt[%d]=%x:\n",
|
|
pwsz,
|
|
L'\0' != *pwsz? L": " : L"",
|
|
pvMemory,
|
|
cbMemory,
|
|
Flags,
|
|
wszAllocator(Flags),
|
|
ibt,
|
|
pbt));
|
|
|
|
if (NULL != pbt && DbgIsSSActive(DBG_SS_CERTLIB))
|
|
{
|
|
DBGPRINTW((MAXDWORD, L"%d: ", ibt));
|
|
|
|
for (int i = 0; i < ARRAYSIZE(pbt->apCaller); i++)
|
|
{
|
|
if (NULL == pbt->apCaller[i])
|
|
{
|
|
break;
|
|
}
|
|
DBGPRINTW((MAXDWORD, L"ln %x;", pbt->apCaller[i]));
|
|
}
|
|
DBGPRINTW((MAXDWORD, L"\n"));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
myRegisterMemDump()
|
|
{
|
|
MEMHEADER *pmh;
|
|
MEMHEADER *pmhEnd;
|
|
LONG cTotal;
|
|
LONG cbTotal;
|
|
|
|
cTotal = 0;
|
|
cbTotal = 0;
|
|
|
|
RegisterMemoryEnterCriticalSection();
|
|
|
|
__try
|
|
{
|
|
pmh = g_rgmh;
|
|
pmhEnd = &g_rgmh[g_cmh];
|
|
|
|
while (pmh < pmhEnd)
|
|
{
|
|
if (0 == (CSM_GLOBALDESTRUCTOR & pmh->Flags) ||
|
|
(MTF_ALLOCTRACE & g_MemTrack))
|
|
{
|
|
if (0 == cTotal)
|
|
{
|
|
if (DbgIsSSActive(DBG_SS_CERTLIB))
|
|
{
|
|
DBGPRINTW((MAXDWORD, L"\n"));
|
|
}
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"%ws: Allocated Memory Blocks:\n",
|
|
s_wszProcess));
|
|
}
|
|
cTotal++;
|
|
cbTotal += pmh->cbMemory;
|
|
|
|
DumpMemBlock(
|
|
L"",
|
|
pmh->pvMemory,
|
|
pmh->cbMemory,
|
|
pmh->Flags,
|
|
pmh->iBackTrace,
|
|
BackTraceFromIndex(pmh->iBackTrace));
|
|
}
|
|
pmh++;
|
|
}
|
|
if (0 != cTotal)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"%ws: Total: c=%x cb=%x\n\n",
|
|
s_wszProcess,
|
|
cTotal,
|
|
cbTotal));
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
RegisterMemoryLeaveCriticalSection();
|
|
}
|
|
|
|
|
|
VOID *
|
|
_VariantMemory(
|
|
IN PROPVARIANT const *pvar,
|
|
OUT DWORD *pFlags,
|
|
OPTIONAL OUT DWORD *pcb)
|
|
{
|
|
VOID *pv = NULL;
|
|
DWORD cb = 0;
|
|
BOOL fString = FALSE;
|
|
|
|
*pFlags = CSM_COTASKALLOC;
|
|
if (NULL != pcb)
|
|
{
|
|
*pcb = 0;
|
|
}
|
|
switch (pvar->vt)
|
|
{
|
|
case VT_BSTR:
|
|
pv = pvar->bstrVal;
|
|
fString = TRUE;
|
|
*pFlags = CSM_SYSALLOC;
|
|
break;
|
|
|
|
case VT_BYREF | VT_BSTR:
|
|
pv = *pvar->pbstrVal;
|
|
fString = TRUE;
|
|
*pFlags = CSM_SYSALLOC;
|
|
break;
|
|
|
|
case VT_LPWSTR:
|
|
pv = pvar->pwszVal;
|
|
fString = TRUE;
|
|
break;
|
|
|
|
case VT_BLOB:
|
|
pv = pvar->blob.pBlobData;
|
|
cb = pvar->blob.cbSize;
|
|
break;
|
|
}
|
|
if (NULL != pcb)
|
|
{
|
|
if (fString)
|
|
{
|
|
cb = (wcslen((WCHAR const *) pv) + 1) * sizeof(WCHAR);
|
|
}
|
|
*pcb = cb;
|
|
}
|
|
return(pv);
|
|
}
|
|
|
|
|
|
VOID
|
|
myRegisterMemAlloc(
|
|
IN VOID const *pv,
|
|
IN LONG cb,
|
|
IN DWORD Flags)
|
|
{
|
|
BACKTRACE bt;
|
|
MEMHEADER *pmh;
|
|
BACKTRACE *pbt;
|
|
DWORD FlagsIn = Flags;
|
|
|
|
Flags &= ~CSM_TRACEASSERT;
|
|
if (CSM_VARIANT == Flags)
|
|
{
|
|
pv = _VariantMemory((PROPVARIANT const *) pv, &Flags, (DWORD *) &cb);
|
|
if (NULL == pv)
|
|
{
|
|
return; // nothing to register
|
|
}
|
|
}
|
|
RegisterMemoryEnterCriticalSection();
|
|
|
|
__try
|
|
{
|
|
static BOOL s_fFirst = TRUE;
|
|
|
|
if (s_fFirst)
|
|
{
|
|
ReadEnvironmentFlags();
|
|
s_fFirst = FALSE;
|
|
}
|
|
if (0 != g_MemTrack)
|
|
{
|
|
// Do not register NULL as an allocation
|
|
CSASSERT(NULL != pv);
|
|
|
|
// see if we already have a reference to this memory
|
|
|
|
pmh = LookupMemHeader(pv);
|
|
if (NULL != pmh)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"%ws: Memory Leak: Tracked memory address reused. Previously allocated:\n",
|
|
s_wszProcess));
|
|
DumpMemBlock(
|
|
L"Memory leak",
|
|
pv,
|
|
pmh->cbMemory,
|
|
pmh->Flags,
|
|
pmh->iBackTrace,
|
|
BackTraceFromIndex(pmh->iBackTrace));
|
|
|
|
CSASSERT(!"Tracked memory address reused");
|
|
FreeMemHeader(pmh);
|
|
}
|
|
|
|
|
|
pmh = AllocMemHeader();
|
|
if (NULL != pmh)
|
|
{
|
|
DWORD ibt;
|
|
|
|
CaptureStackBackTrace(NULL, 0, C_BP_FRAME, bt.apCaller);
|
|
|
|
pbt = LookupBackTrace(&bt, &ibt);
|
|
if (NULL != pbt)
|
|
{
|
|
pbt->cAlloc++;
|
|
pbt->cAllocTotal++;
|
|
pbt->cbAlloc += cb;
|
|
pbt->cbAllocTotal += cb;
|
|
}
|
|
else
|
|
{
|
|
pbt = AllocBackTrace(&ibt);
|
|
if (NULL != pbt)
|
|
{
|
|
pbt->cAlloc = 1;
|
|
pbt->cAllocTotal = 1;
|
|
pbt->cbAlloc = cb;
|
|
pbt->cbAllocTotal = cb;
|
|
CopyMemory(pbt->apCaller, bt.apCaller, sizeof(pbt->apCaller));
|
|
}
|
|
}
|
|
if (NULL != pbt)
|
|
{
|
|
pmh->iBackTrace = ibt;
|
|
pmh->pvMemory = pv;
|
|
pmh->cbMemory = cb;
|
|
pmh->Flags = Flags | (CSM_TRACEASSERT & FlagsIn);
|
|
|
|
CSASSERT(ARRAYSIZE(g_armAlloc) > Flags);
|
|
g_armAlloc[Flags].cAlloc++;
|
|
g_armAlloc[Flags].cAllocTotal++;
|
|
if (MTF_ALLOCTRACE & g_MemTrack)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"Alloc: pmh=%x: pv=%x cb=%x f=%x(%ws) -- pbt[%d]=%x: c=%x, cb=%x\n",
|
|
pmh,
|
|
pmh->pvMemory,
|
|
pmh->cbMemory,
|
|
pmh->Flags,
|
|
wszAllocator(pmh->Flags),
|
|
SAFE_SUBTRACT_POINTERS(pbt, g_rgbt),
|
|
pbt,
|
|
pbt->cAlloc,
|
|
pbt->cbAlloc));
|
|
if (MTF_STACKTRACE & g_MemTrack)
|
|
{
|
|
DumpMemBlock(
|
|
L"Alloc Trace memory block",
|
|
pv,
|
|
pmh->cbMemory, // cbMemory
|
|
pmh->Flags, // Flags
|
|
pmh->iBackTrace, // ibt
|
|
pbt);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FreeMemHeader(pmh);
|
|
}
|
|
} // if no problem allocating pmh
|
|
} // if g_MemTrack
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
RegisterMemoryLeaveCriticalSection();
|
|
}
|
|
|
|
|
|
VOID
|
|
myRegisterMemFree(
|
|
IN VOID const *pv,
|
|
IN DWORD Flags)
|
|
{
|
|
MEMHEADER *pmh;
|
|
|
|
if (NULL == pv)
|
|
{
|
|
return;
|
|
}
|
|
if (CSM_VARIANT == Flags)
|
|
{
|
|
pv = _VariantMemory((PROPVARIANT const *) pv, &Flags, NULL);
|
|
if (NULL == pv)
|
|
{
|
|
return; // nothing to register
|
|
}
|
|
}
|
|
RegisterMemoryEnterCriticalSection();
|
|
CSASSERT(CSM_MAX > (~CSM_GLOBALDESTRUCTOR & Flags));
|
|
|
|
__try
|
|
{
|
|
pmh = LookupMemHeader(pv);
|
|
if (NULL != pmh)
|
|
{
|
|
BACKTRACE *pbt = BackTraceFromIndex(pmh->iBackTrace);
|
|
|
|
if (CSM_GLOBALDESTRUCTOR & Flags)
|
|
{
|
|
if ((CSM_GLOBALDESTRUCTOR | pmh->Flags) != Flags)
|
|
{
|
|
BACKTRACE bt;
|
|
|
|
CaptureStackBackTrace(NULL, 0, C_BP_FRAME, bt.apCaller);
|
|
DumpMemBlock(
|
|
L"Wrong memory allocator for global destructor",
|
|
pv,
|
|
MAXDWORD, // cbMemory
|
|
MAXDWORD, // Flags
|
|
MAXDWORD, // ibt
|
|
&bt);
|
|
CSASSERT(!"Wrong memory allocator for global destructor");
|
|
}
|
|
else
|
|
{
|
|
pmh->Flags |= CSM_GLOBALDESTRUCTOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_armAlloc[Flags].cAlloc--;
|
|
|
|
pbt->cAlloc--;
|
|
pbt->cbAlloc -= pmh->cbMemory;
|
|
|
|
if (CSM_GLOBALDESTRUCTOR & pmh->Flags)
|
|
{
|
|
Flags |= CSM_GLOBALDESTRUCTOR;
|
|
}
|
|
if (CSM_TRACEASSERT & pmh->Flags)
|
|
{
|
|
Flags |= CSM_TRACEASSERT;
|
|
}
|
|
if (pmh->Flags != Flags)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"%ws: Wrong memory allocator: Freed with %ws, Allocated by %ws\n",
|
|
s_wszProcess,
|
|
wszFreeer(Flags),
|
|
wszAllocator(pmh->Flags)));
|
|
DumpMemBlock(
|
|
L"Wrong memory allocator",
|
|
pv,
|
|
pmh->cbMemory,
|
|
pmh->Flags,
|
|
pmh->iBackTrace,
|
|
BackTraceFromIndex(pmh->iBackTrace));
|
|
CSASSERT(pmh->Flags == Flags);
|
|
}
|
|
else if (MTF_FREETRACE & g_MemTrack)
|
|
{
|
|
DBGPRINTW((
|
|
DBG_SS_CERTLIB,
|
|
L"Free: pmh=%x: pv=%x cb=%x f=%x(%ws) -- pbt[%d]=%x: c=%x, cb=%x\n",
|
|
pmh,
|
|
pv,
|
|
pmh->cbMemory,
|
|
pmh->Flags,
|
|
wszAllocator(pmh->Flags),
|
|
pmh->iBackTrace,
|
|
pbt,
|
|
pbt->cAlloc,
|
|
pbt->cbAlloc));
|
|
if (MTF_STACKTRACE & g_MemTrack)
|
|
{
|
|
BACKTRACE bt;
|
|
|
|
CaptureStackBackTrace(NULL, 0, C_BP_FRAME, bt.apCaller);
|
|
DumpMemBlock(
|
|
L"Free Trace memory block(alloc)",
|
|
pv,
|
|
pmh->cbMemory, // cbMemory
|
|
pmh->Flags, // Flags
|
|
pmh->iBackTrace, // ibt
|
|
pbt);
|
|
DumpMemBlock(
|
|
L"Free Trace memory block(free)",
|
|
pv,
|
|
pmh->cbMemory, // cbMemory
|
|
pmh->Flags, // Flags
|
|
MAXDWORD, // ibt
|
|
&bt);
|
|
}
|
|
}
|
|
FreeMemHeader(pmh);
|
|
}
|
|
}
|
|
else if (MTF_UNREGISTERED & g_MemTrack)
|
|
{
|
|
BACKTRACE bt;
|
|
|
|
CaptureStackBackTrace(NULL, 0, C_BP_FRAME, bt.apCaller);
|
|
DumpMemBlock(
|
|
L"Unregistered memory block",
|
|
pv,
|
|
MAXDWORD, // cbMemory
|
|
MAXDWORD, // Flags
|
|
MAXDWORD, // ibt
|
|
&bt);
|
|
CSASSERT(!"Unregistered memory block");
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
RegisterMemoryLeaveCriticalSection();
|
|
}
|
|
|
|
|
|
DWORD
|
|
myFormatMessageW(
|
|
IN DWORD dwFlags,
|
|
IN LPCVOID lpSource,
|
|
IN DWORD dwMessageId,
|
|
IN DWORD dwLanguageId,
|
|
OUT LPWSTR lpBuffer,
|
|
IN DWORD nSize,
|
|
IN va_list *Arguments)
|
|
{
|
|
DWORD cwc;
|
|
|
|
cwc = FormatMessage(
|
|
dwFlags,
|
|
lpSource,
|
|
dwMessageId,
|
|
dwLanguageId,
|
|
lpBuffer,
|
|
nSize,
|
|
Arguments);
|
|
if (cwc != 0 && (FORMAT_MESSAGE_ALLOCATE_BUFFER & dwFlags))
|
|
{
|
|
myRegisterMemAlloc(
|
|
*(WCHAR **) lpBuffer,
|
|
(cwc + 1) * sizeof(WCHAR),
|
|
CSM_LOCALALLOC);
|
|
}
|
|
return(cwc);
|
|
}
|
|
|
|
|
|
HLOCAL
|
|
myLocalAlloc(
|
|
IN UINT uFlags,
|
|
IN UINT uBytes)
|
|
{
|
|
HLOCAL hMem;
|
|
|
|
// one of these should always be specified (see LocalAlloc specification)
|
|
assert((LMEM_FIXED == (uFlags & LMEM_FIXED)) ||
|
|
(LMEM_MOVEABLE == (uFlags & LMEM_MOVEABLE)) );
|
|
|
|
hMem = LocalAlloc(uFlags, uBytes);
|
|
if (NULL != hMem)
|
|
{
|
|
myRegisterMemAlloc(hMem, uBytes, CSM_LOCALALLOC);
|
|
}
|
|
return(hMem);
|
|
}
|
|
|
|
|
|
HLOCAL
|
|
myLocalReAlloc(
|
|
IN HLOCAL hMem,
|
|
IN UINT uBytes,
|
|
IN UINT uFlags)
|
|
{
|
|
HLOCAL hMemNew;
|
|
|
|
// if realloc called without MOVEABLE flag, realloc can't relocate allocation
|
|
assert(LMEM_MOVEABLE == (uFlags & LMEM_MOVEABLE));
|
|
|
|
hMemNew = LocalReAlloc(hMem, uBytes, uFlags);
|
|
if (NULL != hMemNew)
|
|
{
|
|
myRegisterMemFree(hMem, CSM_LOCALALLOC);
|
|
myRegisterMemAlloc(hMemNew, uBytes, CSM_LOCALALLOC);
|
|
}
|
|
|
|
return(hMemNew);
|
|
}
|
|
|
|
|
|
HLOCAL
|
|
myLocalFree(
|
|
IN HLOCAL hMem)
|
|
{
|
|
myRegisterMemFree(hMem, CSM_LOCALALLOC);
|
|
return(LocalFree(hMem));
|
|
}
|
|
|
|
|
|
VOID *
|
|
myCoTaskMemAlloc(
|
|
IN ULONG cb)
|
|
{
|
|
VOID *pv;
|
|
|
|
pv = CoTaskMemAlloc(cb);
|
|
if (NULL != pv)
|
|
{
|
|
myRegisterMemAlloc(pv, cb, CSM_COTASKALLOC);
|
|
}
|
|
return(pv);
|
|
}
|
|
|
|
|
|
VOID *
|
|
myCoTaskMemRealloc(
|
|
IN VOID *pv,
|
|
IN ULONG cb)
|
|
{
|
|
VOID *pvNew;
|
|
|
|
pvNew = CoTaskMemRealloc(pv, cb);
|
|
if (NULL != pvNew)
|
|
{
|
|
myRegisterMemFree(pv, CSM_COTASKALLOC);
|
|
myRegisterMemAlloc(pvNew, cb, CSM_COTASKALLOC);
|
|
}
|
|
return(pvNew);
|
|
}
|
|
|
|
|
|
VOID
|
|
myCoTaskMemFree(
|
|
IN VOID *pv)
|
|
{
|
|
myRegisterMemFree(pv, CSM_COTASKALLOC);
|
|
CoTaskMemFree(pv);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myStringFromCLSID(
|
|
IN REFCLSID rclsid,
|
|
OUT LPOLESTR FAR *ppwsz)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = StringFromCLSID(rclsid, ppwsz);
|
|
_JumpIfError(hr, error, "StringFromCLSID");
|
|
|
|
if (NULL != *ppwsz)
|
|
{
|
|
myRegisterMemAlloc(
|
|
*ppwsz, (wcslen(*ppwsz) + 1) * sizeof(WCHAR),
|
|
CSM_COTASKALLOC);
|
|
}
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myStringFromIID(
|
|
IN REFIID rclsid,
|
|
OUT LPOLESTR FAR *ppwsz)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = StringFromIID(rclsid, ppwsz);
|
|
_JumpIfError(hr, error, "StringFromIID");
|
|
|
|
if (NULL != *ppwsz)
|
|
{
|
|
myRegisterMemAlloc(
|
|
*ppwsz, (wcslen(*ppwsz) + 1) * sizeof(WCHAR),
|
|
CSM_COTASKALLOC);
|
|
}
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
BSTR
|
|
mySysAllocString(
|
|
IN const OLECHAR *pwszIn)
|
|
{
|
|
BSTR str;
|
|
|
|
str = SysAllocString(pwszIn);
|
|
if (NULL != str)
|
|
{
|
|
myRegisterMemAlloc(str, (wcslen(pwszIn) + 1) * sizeof(WCHAR), CSM_SYSALLOC);
|
|
}
|
|
return(str);
|
|
}
|
|
|
|
|
|
INT
|
|
mySysReAllocString(
|
|
IN OUT BSTR *pstr,
|
|
IN const OLECHAR *pwszIn)
|
|
{
|
|
BSTR str = *pstr;
|
|
INT i;
|
|
|
|
i = SysReAllocString(pstr, pwszIn);
|
|
if (i)
|
|
{
|
|
myRegisterMemFree(str, CSM_SYSALLOC);
|
|
myRegisterMemAlloc(*pstr, (wcslen(pwszIn) + 1) * sizeof(WCHAR), CSM_SYSALLOC);
|
|
}
|
|
return(i);
|
|
}
|
|
|
|
|
|
BSTR
|
|
mySysAllocStringLen(
|
|
IN const OLECHAR *pwcIn,
|
|
IN UINT cwc)
|
|
{
|
|
BSTR str;
|
|
|
|
str = SysAllocStringLen(pwcIn, cwc);
|
|
if (NULL != str)
|
|
{
|
|
myRegisterMemAlloc(str, cwc * sizeof(WCHAR), CSM_SYSALLOC);
|
|
}
|
|
return(str);
|
|
}
|
|
|
|
|
|
INT
|
|
mySysReAllocStringLen(
|
|
IN OUT BSTR *pstr,
|
|
IN const OLECHAR *pwcIn,
|
|
IN UINT cwc)
|
|
{
|
|
BSTR str = *pstr;
|
|
INT i;
|
|
|
|
i = SysReAllocStringLen(pstr, pwcIn, cwc);
|
|
if (i)
|
|
{
|
|
myRegisterMemFree(str, CSM_SYSALLOC);
|
|
myRegisterMemAlloc(*pstr, cwc * sizeof(WCHAR), CSM_SYSALLOC);
|
|
}
|
|
return(i);
|
|
}
|
|
|
|
|
|
VOID
|
|
mySysFreeString(
|
|
IN BSTR str)
|
|
{
|
|
if (NULL != str)
|
|
{
|
|
myRegisterMemFree(str, CSM_SYSALLOC);
|
|
}
|
|
SysFreeString(str);
|
|
}
|
|
|
|
|
|
BSTR
|
|
mySysAllocStringByteLen(
|
|
LPCSTR pszIn,
|
|
UINT cb)
|
|
{
|
|
BSTR str;
|
|
|
|
str = SysAllocStringByteLen(pszIn, cb);
|
|
if (NULL != str)
|
|
{
|
|
myRegisterMemAlloc(str, cb, CSM_SYSALLOC);
|
|
}
|
|
return(str);
|
|
}
|
|
|
|
|
|
VOID
|
|
_RegisterVariantMemAlloc(
|
|
IN PROPVARIANT *pvar)
|
|
{
|
|
VOID *pv;
|
|
DWORD Flags;
|
|
DWORD cb;
|
|
|
|
pv = _VariantMemory(pvar, &Flags, &cb);
|
|
if (NULL != pv)
|
|
{
|
|
myRegisterMemAlloc(pv, cb, Flags);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
_RegisterVariantMemFree(
|
|
IN PROPVARIANT *pvar)
|
|
{
|
|
VOID *pv;
|
|
DWORD Flags;
|
|
|
|
pv = _VariantMemory(pvar, &Flags, NULL);
|
|
if (NULL != pv)
|
|
{
|
|
myRegisterMemFree(pv, Flags);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myPropVariantClear(
|
|
IN PROPVARIANT *pvar)
|
|
{
|
|
_RegisterVariantMemFree(pvar);
|
|
return(PropVariantClear(pvar));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myVariantClear(
|
|
IN VARIANTARG *pvar)
|
|
{
|
|
_RegisterVariantMemFree((PROPVARIANT *) pvar);
|
|
return(VariantClear(pvar));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myVariantChangeType(
|
|
OUT VARIANTARG *pvarDest,
|
|
IN VARIANTARG *pvarSrc,
|
|
IN unsigned short wFlags,
|
|
IN VARTYPE vt)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// if converting in-place, memory will be freed by the API call
|
|
|
|
if (pvarDest == pvarSrc)
|
|
{
|
|
_RegisterVariantMemFree((PROPVARIANT *) pvarSrc);
|
|
}
|
|
hr = VariantChangeType(pvarDest, pvarSrc, wFlags, vt);
|
|
_RegisterVariantMemAlloc((PROPVARIANT *) pvarDest);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myVariantChangeTypeEx(
|
|
OUT VARIANTARG *pvarDest,
|
|
IN VARIANTARG *pvarSrc,
|
|
IN LCID lcid,
|
|
IN unsigned short wFlags,
|
|
IN VARTYPE vt)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// if converting in-place, memory will be freed by the API call
|
|
|
|
if (pvarDest == pvarSrc)
|
|
{
|
|
_RegisterVariantMemFree((PROPVARIANT *) pvarSrc);
|
|
}
|
|
hr = VariantChangeTypeEx(pvarDest, pvarSrc, lcid, wFlags, vt);
|
|
_RegisterVariantMemAlloc((PROPVARIANT *) pvarDest);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID *
|
|
myNew(
|
|
IN size_t size)
|
|
{
|
|
VOID *pv;
|
|
|
|
pv = LocalAlloc(LMEM_FIXED, size);
|
|
if (NULL != pv)
|
|
{
|
|
myRegisterMemAlloc(pv, size, CSM_NEW);
|
|
}
|
|
return(pv);
|
|
}
|
|
|
|
|
|
VOID
|
|
myDelete(
|
|
IN VOID *pv)
|
|
{
|
|
myRegisterMemFree(pv, CSM_NEW);
|
|
LocalFree(pv);
|
|
}
|
|
|
|
|
|
BOOL
|
|
myAllocateAndInitializeSid(
|
|
IN PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
|
|
IN BYTE nSubAuthorityCount,
|
|
IN DWORD nSubAuthority0,
|
|
IN DWORD nSubAuthority1,
|
|
IN DWORD nSubAuthority2,
|
|
IN DWORD nSubAuthority3,
|
|
IN DWORD nSubAuthority4,
|
|
IN DWORD nSubAuthority5,
|
|
IN DWORD nSubAuthority6,
|
|
IN DWORD nSubAuthority7,
|
|
OUT PSID *ppSid)
|
|
{
|
|
BOOL b;
|
|
|
|
b = AllocateAndInitializeSid(
|
|
pIdentifierAuthority,
|
|
nSubAuthorityCount,
|
|
nSubAuthority0,
|
|
nSubAuthority1,
|
|
nSubAuthority2,
|
|
nSubAuthority3,
|
|
nSubAuthority4,
|
|
nSubAuthority5,
|
|
nSubAuthority6,
|
|
nSubAuthority7,
|
|
ppSid);
|
|
if (b && NULL != *ppSid)
|
|
{
|
|
myRegisterMemAlloc(*ppSid, 32, CSM_SID);
|
|
}
|
|
return(b);
|
|
}
|
|
|
|
|
|
VOID *
|
|
myFreeSid(
|
|
IN PSID pSid)
|
|
{
|
|
myRegisterMemFree(pSid, CSM_SID);
|
|
return(FreeSid(pSid));
|
|
}
|
|
|
|
#endif // DBG_CERTSRV
|