Windows2003-3790/inetcore/outlookexpress/wabw/wabapi/memory.c
2020-09-30 16:53:55 +02:00

904 lines
23 KiB
C

/*
- MEMORY.C
-
*
* Contains the following functions exported from MAPIX.DLL:
* MAPIAllocateBuffer
* MAPIAllocateMore
* MAPIFreeBuffer
*
* Contains the following functions handed to providers:
* MAPIAllocateBufferProv
* MAPIAllocateMoreProv
*
* Contains the following functions private to MAPIX.DLL:
* MAPIAllocateBufferExt
* MAPIAllocateMoreExt
*/
#include "_apipch.h"
#define _MEMORY_C
// Critical section for serializing heap access
#if (defined(WIN32) || defined(WIN16)) && !defined(MAC)
CRITICAL_SECTION csHeap;
#endif
#if (defined(WIN32) || defined(WIN16)) && !defined(MAC)
CRITICAL_SECTION csMapiInit;
#endif
#if (defined(WIN32) || defined(WIN16)) && !defined(MAC)
CRITICAL_SECTION csMapiSearchPath;
#endif
#ifdef WIN32
/* This is the entire 32-bit implementation for instance globals. */
VOID FAR *pinstX = NULL;
#endif
#ifndef MAC
// DefineInstList(lpInstUtil);
#endif
#ifdef MAC
#include <utilmac.h>
#define PvGetInstanceGlobals() PvGetInstanceGlobalsMac(kInstMAPIX)
#define PvGetInstanceGlobalsEx(_x) PvGetInstanceGlobalsMac(kInstMAPIU)
#endif
// Buffer link overhead.
// Blocks of memory obtained with MAPIAllocateMore are linked to a
// block obtained with MAPIAllocateBuffer, so that the whole chain
// may be freed with one call to MAPIFreeBuffer.
typedef struct _BufInternal * LPBufInternal;
typedef struct _BufInternal
{
#ifdef DEBUG
ULONG ulPad;
HLH hHeap;
#endif
ULONG ulAllocFlags;
LPBufInternal pLink;
} BufInternal;
// Values for ulAllocFlags. This dword contains two kinds of
// information:
// = In the high-order word, flags telling whether or not
// the block is the head of an allocation chain, and whether
// the block contains additional debugging information.
// = In the low-order word, an enum telling which heap
// it was allocated from.
#ifdef DEBUG
#define ALLOC_DEBUG ((ULONG) 0x40000000)
#else
#define ALLOC_DEBUG ((ULONG) 0x00000000)
#endif
#define ALLOC_WITH_ALLOC (((ULONG) 0x10000000) | ALLOC_DEBUG)
#define ALLOC_WITH_ALLOC_MORE (((ULONG) 0x20000000) | ALLOC_DEBUG)
#define FLAGSMASK ((ULONG) 0xFFFF0000)
#define GetFlags(_fl) ((ULONG) (_fl) & FLAGSMASK)
#define heapidClient 1
#define heapidProvider 2
#define HEAPIDMASK 0xFFFF
#define GetHeapid(_fl) (((int)(_fl)) & HEAPIDMASK)
// Conversion macros
#define INT_SIZE(a) ((a) + sizeof (BufInternal))
#define LPBufExtFromLPBufInt( PBUFINT ) \
((LPVOID)(((LPBYTE) PBUFINT) + sizeof(BufInternal)))
#define LPBufIntFromLPBufExt( PBUFEXT ) \
((LPBufInternal)(((LPBYTE) PBUFEXT) - sizeof(BufInternal)))
#ifdef DEBUG
// Internal stuff for checking memory buffer consistency.
// The flag fAssertBadBlocks governs whether we generate an
// assert or a debug trace when passed a bad block.
// By default, we'll assert.
// In the macros, _p is the address of a memory block;
// _s is a string describing what's wrong with it
static int fAssertBadBlocks = -1; // read from INI file
#define TellBadBlock(_p, _s) \
{ if (fAssertBadBlocks == 1) \
TrapSz1( TEXT("MAPIAlloc: memory block %08lX ") _s TEXT("\n"), _p); \
else \
TraceSz1( TEXT("MAPIAlloc: memory block %08lX ") _s TEXT("\n"), _p); }
#define TellBadBlockInt(_p, _s) \
{ if (fAssertBadBlocks == 1) \
TrapSz1( TEXT("MAPIAlloc: memory block %08lX ") _s TEXT("\n"), LPBufExtFromLPBufInt(_p)); \
else \
TraceSz1( TEXT("MAPIAlloc: memory block %08lX ") _s TEXT("\n"), LPBufExtFromLPBufInt(_p)); }
BOOL FValidAllocChain(LPBufInternal lpBuf);
#else
#define TellBadBlock(_p, _s)
#define TellBadBlockInt(_p, _s)
#endif
/* Internal Prototypes */
STDMETHODIMP_(SCODE)
MAPIAllocateBufferExt(
int heapid,
ULONG ulSize,
LPVOID * lppv);
STDMETHODIMP_(SCODE)
MAPIAllocateMoreExt(
int heapid,
ULONG ulSize,
LPVOID lpv,
LPVOID * lppv);
SCODE ScGetHlh(int heapid, HLH FAR *phlh);
#ifndef MAC
#ifndef WIN32
#pragma SEGMENT(MAPI_Core1)
#endif
#else
#pragma code_seg("mapi", "fixed")
#endif
/*----------------------------------------------*/
/* Beginning of Client Allocators */
/*----------------------------------------------*/
/*
* MAPIAllocateBuffer
*
* Purpose:
* Allocates a memory buffer on behalf of the client. Can be
* freed with MAPIFreeBuffer().
*
* Arguments:
* ulSize in Size, in bytes, of the buffer to be allocated.
* lppv out Pointer to variable where the address of the
* allocated memory will be returned.
*
* Assumes:
* Should be called from a client and therefore will allocate
* memory from the Client heap - pinst->hlhClient.
*
* Returns:
* HRESULT: created from scodes described below.
*
* Side effects:
* Increments allocation count in the INST.
*
* Errors:
* MAPI_E_INSUFFICIENT_MEMORY Allocation failed.
* MAPI_E_INVALID_PARAMETER Second argument is invalid.
* MAPI_E_INVALID_PARAMETER ulSize is out of range (>= 65535 on Win16).
*/
STDMETHODIMP_(SCODE)
MAPIAllocateBuffer(ULONG ulSize, LPVOID * lppv)
{
SCODE sc = S_OK;
if (lpfnAllocateBufferExternal) {
return(lpfnAllocateBufferExternal(ulSize, lppv));
}
#ifdef DEBUG
// Initialize flag that controls how noisy we are about invalid
// blocks passed to us.
if (fAssertBadBlocks == -1)
{
fAssertBadBlocks = GetPrivateProfileInt( TEXT("General"), TEXT("AssertBadBlocks"),
1, TEXT("WABDBG.INI"));
}
#endif
#ifdef PARAMETER_VALIDATION
if (IsBadWritePtr((LPVOID) lppv, sizeof (LPVOID)))
{
DebugTraceArg(MAPIAllocateBuffer, TEXT("lppv fails address check"));
return MAPI_E_INVALID_PARAMETER;
}
#endif
sc = MAPIAllocateBufferExt(heapidClient, ulSize, lppv);
DebugTraceSc(MAPIAllocateBuffer, sc);
return sc;
}
/*
* MAPIAllocateMore
*
* Purpose:
* Allocates a linked memory buffer on behalf of the client,
* in such a way that it can be freed with one call to MAPIFreeBuffer
* (passing the buffer the client originally allocated with
* MAPIAllocateBuffer).
*
* Arguments:
* ulSize in Size, in bytes, of the buffer to be allocated.
* lpv in Pointer to a buffer allocated with MAPIAllocateBuffer.
* lppv out Pointer to variable where the address of the
* allocated memory will be returned.
*
* Assumes:
* Validates that lpBufOrig and lppv point to writable memory.
* Validate that ulSize is less than 64K (on Win16 only) and that
* lpBufOrig was allocated with MAPIAllocateBuffer.
* Should be called from a client and therefore will allocate
* memory from the Client heap - pinstUtil->hlhClient.
*
* Returns:
* HRESULT: created from scodes described below.
*
* Side effects:
* None
*
* Errors:
* MAPI_E_INSUFFICIENT_MEMORY Allocation failed.
* MAPI_E_INVALID_PARAMETER Second or third argument is invalid.
* MAPI_E_INVALID_PARAMETER ulSize is out of range (>= 65535).
*/
STDMETHODIMP_(SCODE)
MAPIAllocateMore(ULONG ulSize, LPVOID lpv, LPVOID * lppv)
{
SCODE sc = S_OK;
if (lpfnAllocateMoreExternal) {
return(lpfnAllocateMoreExternal(ulSize, lpv, lppv));
}
#ifdef PARAMETER_VALIDATION
/*LPBufInternal lpBufOrig = LPBufIntFromLPBufExt(lpv);
if (IsBadWritePtr(lpBufOrig, sizeof(BufInternal)))
{
TellBadBlock(lpv, "fails address check");
return MAPI_E_INVALID_PARAMETER;
}
if (GetFlags(lpBufOrig->ulAllocFlags) != ALLOC_WITH_ALLOC)
{
TellBadBlock(lpv, "has invalid allocation flags");
return MAPI_E_INVALID_PARAMETER;
}
*/
if (IsBadWritePtr(lppv, sizeof(LPVOID)))
{
DebugTraceArg(MAPIAllocateMore, TEXT("lppv fails address check"));
return MAPI_E_INVALID_PARAMETER;
}
#endif /* PARAMETER_VALIDATION */
sc = MAPIAllocateMoreExt(heapidClient, ulSize, lpv, lppv);
DebugTraceSc(MAPIAllocateMore, sc);
return sc;
}
/*
* MAPIFreeBuffer
*
* Purpose:
* Frees a memory block (or chain of blocks).
* Frees any additional blocks linked with MAPIAllocateMore to
* the buffer argument. Uses hHeap in the block header to
* determine which heap to free into.
*
* Arguments:
* lpv Pointer to a buffer allocated with MAPIAllocateBuffer.
* lpv may be null, in which case we return immediately.
*
* Assumes:
* This routine validates that lpv points to writable memory,
* and was allocated with MAPIAllocateBuffer.
*
* Returns:
* O if successful, lpv if unsuccessful.
* If we are partially successful, i.e. the original block is
* freed but the chain is corrupt further on, returns 0.
*
*/
#ifndef WIN16
STDAPI_(ULONG)
MAPIFreeBuffer(LPVOID lpv)
#else
ULONG FAR PASCAL
MAPIFreeBuffer(LPVOID lpv)
#endif
{
LPBufInternal lpBufInt;
LPBufInternal lpT;
HLH hlh;
int heapid;
if (!lpv)
return(0L); // for callers who don't check for NULL themselves.
if (lpfnFreeBufferExternal) {
return(lpfnFreeBufferExternal(lpv));
}
lpBufInt = LPBufIntFromLPBufExt(lpv);
#ifdef PARAMETER_VALIDATION
// NOTE: these validations should be exactly the same as those
// that cause FValidAllocChain to return FALSE.
if (IsBadWritePtr(lpBufInt, sizeof(BufInternal)))
{
TellBadBlock(lpv, TEXT("fails address check"));
return E_FAIL;
}
if (GetFlags(lpBufInt->ulAllocFlags) != ALLOC_WITH_ALLOC)
{
TellBadBlock(lpv, TEXT("has invalid allocation flags"));
return E_FAIL;
}
#endif
// No CS used, as the internal heap is serialized.
// Only the AllocMore needs a CS, the Free does not; freeing
// a block whilst someone else is allocing more against it is
// asking for trouble!
// Note also that neither MAPIAllocateBuffer nor MAPIAllocateMore
// allow callers to use them when pinst->cRef == 0. MAPIFreeBuffer
// allows itself to be called in that case because simple MAPI
// needs to be able to free memory up until the DLL is unloaded.
#ifdef DEBUG
// This call checks flags and addresses for the whole chain.
// This means that, in DEBUG, we'll leak all of a chain that's
// corrupted after the first block. In SHIP, on the other hand,
// we'll free everything up until the broken link.
// But we do not return an error, for consistency.
if (!FValidAllocChain(lpBufInt))
goto ret;
#endif
// Free the first block, using its allocator
lpT = lpBufInt->pLink;
heapid = GetHeapid(lpBufInt->ulAllocFlags);
if (ScGetHlh(heapid, &hlh))
{
DebugTrace( TEXT("MAPIFreeBuffer: playing in a heap that's gone\n"));
return E_FAIL;
}
Assert(hlh == lpBufInt->hHeap);
LH_Free(hlh, lpBufInt);
lpBufInt = lpT;
while (lpBufInt)
{
// NOTE: these validations should be exactly the same as those
// that cause FValidAllocChain to return FALSE.
if (IsBadWritePtr(lpBufInt, sizeof(BufInternal)) ||
GetFlags(lpBufInt->ulAllocFlags) != ALLOC_WITH_ALLOC_MORE)
goto ret;
lpT = lpBufInt->pLink;
// Usually, chained buffers live in the same heap. We can do
// less work in this common case.
if ((int) GetHeapid(lpBufInt->ulAllocFlags) == heapid)
LH_Free(hlh, lpBufInt);
else
{
HLH hlhMore;
if (!ScGetHlh(GetHeapid(lpBufInt->ulAllocFlags), &hlhMore))
LH_Free(hlhMore, lpBufInt);
else
{
DebugTrace(TEXT("MAPIFreeBuffer: playing in a chained heap that's gone\n"));
}
}
lpBufInt = lpT;
}
ret:
return 0;
}
#ifdef OLD_STUFF
/*----------------------------------------------*/
/* Beginning of Provider Allocators */
/*----------------------------------------------*/
/*
* MAPIAllocateBufferProv
*
* Purpose:
* Same as MAPIAllocateBuffer except uses the Service
* Providers heap - pinst->hlhProvider.
*/
STDMETHODIMP_(SCODE)
MAPIAllocateBufferProv(ULONG ulSize, LPVOID * lppv)
{
SCODE sc = S_OK;
#ifdef DEBUG
// Initialize flag that controls how noisy we are about invalid
// blocks passed to us.
if (fAssertBadBlocks == -1)
{
fAssertBadBlocks = GetPrivateProfileInt("General", "AssertBadBlocks",
1, "WABDBG.INI");
}
#endif
#ifdef PARAMETER_VALIDATION
if (IsBadWritePtr((LPVOID) lppv, sizeof (LPVOID)))
{
DebugTraceArg(MAPIAllocateBuffer, TEXT("lppv fails address check"));
return MAPI_E_INVALID_PARAMETER;
}
#endif
sc = MAPIAllocateBufferExt(heapidProvider, ulSize, lppv);
DebugTraceSc(MAPIAllocateBufferProv, sc);
return sc;
}
/*
* MAPIAllocateMoreProv
*
* Purpose:
* Same as MAPIAllocateMore except uses the Service
* Providers heap - pinst->hlhProvider.
*/
STDMETHODIMP_(SCODE)
MAPIAllocateMoreProv(ULONG ulSize, LPVOID lpv, LPVOID * lppv)
{
SCODE sc = S_OK;
#ifdef PARAMETER_VALIDATION
LPBufInternal lpBufOrig = LPBufIntFromLPBufExt(lpv);
if (IsBadWritePtr(lpBufOrig, sizeof(BufInternal)))
{
TellBadBlock(lpv, "fails address check");
return MAPI_E_INVALID_PARAMETER;
}
if (GetFlags(lpBufOrig->ulAllocFlags) != ALLOC_WITH_ALLOC)
{
TellBadBlock(lpv, "has invalid allocation flags");
return MAPI_E_INVALID_PARAMETER;
}
if (IsBadWritePtr(lppv, sizeof(LPVOID)))
{
DebugTraceArg(MAPIAllocateMore, TEXT("lppv fails address check"));
return MAPI_E_INVALID_PARAMETER;
}
#endif /* PARAMETER_VALIDATION */
sc = MAPIAllocateMoreExt(heapidProvider, ulSize, lpv, lppv);
DebugTraceSc(MAPIAllocateMoreProv, sc);
return sc;
}
#endif
/*----------------------------------------------*/
/* Beginning of Extended Allocators */
/*----------------------------------------------*/
/*
* MAPIAllocateBufferExt
*
* Purpose:
* Allocates a memory buffer on the specified heap. Can be
* freed with MAPIFreeBuffer().
*
* Arguments:
* heapid in identifies the heap we wish to allocate in
* pinst in Pointer to our instance data
* ulSize in Size, in bytes, of the buffer to be allocated.
* lppv out Pointer to variable where the address of the
* allocated memory will be returned.
*
* Returns:
* sc Indicating error if any (see below)
*
* Side effects:
* Increments allocation count in the INST.
*
* Errors:
* MAPI_E_INSUFFICIENT_MEMORY Allocation failed.
* MAPI_E_INVALID_PARAMETER Second argument is invalid.
* MAPI_E_INVALID_PARAMETER ulSize is out of range (>= 65535 on Win16).
*/
STDMETHODIMP_(SCODE)
MAPIAllocateBufferExt(int heapid, ULONG ulSize, LPVOID * lppv)
{
SCODE sc = S_OK;
LPBufInternal lpBufInt;
HLH hlh;
// Don't allow allocation to wrap across 32 bits, or to exceed 64K
// under win16.
if ( ulSize > INT_SIZE (ulSize)
#ifdef WIN16
|| (INT_SIZE(ulSize) >= 0x10000)
#endif
)
{
DebugTrace(TEXT("MAPIAllocateBuffer: ulSize %ld is way too big\n"), ulSize);
sc = MAPI_E_NOT_ENOUGH_MEMORY;
goto ret;
}
if (sc = ScGetHlh(heapid, &hlh))
goto ret;
lpBufInt = (LPBufInternal)LH_Alloc(hlh, (UINT) INT_SIZE(ulSize));
if (lpBufInt)
{
#ifdef DEBUG
lpBufInt->hHeap = hlh;
#endif
lpBufInt->pLink = NULL;
lpBufInt->ulAllocFlags = ALLOC_WITH_ALLOC | heapid;
*lppv = (LPVOID) LPBufExtFromLPBufInt(lpBufInt);
}
else
{
DebugTrace(TEXT("MAPIAllocateBuffer: not enough memory for %ld\n"), ulSize);
sc = MAPI_E_NOT_ENOUGH_MEMORY;
}
ret:
return sc;
}
/*
* MAPIAllocateMoreExt
*
* Purpose:
* Allocates a linked memory buffer on the specified heap, in such
* a way that it can be freed with one call to MAPIFreeBuffer
* (passing the buffer the client originally allocated with
* MAPIAllocateBuffer).
*
* Arguments:
* heapid in Identifies the heap we wish to allocate in
* ulSize in Size, in bytes, of the buffer to be allocated.
* lpv in Pointer to a buffer allocated with MAPIAllocateBuffer.
* lppv out Pointer to variable where the address of the
* allocated memory will be returned.
*
* Assumes:
* Validates that lpBufOrig and lppv point to writable memory.
* Validate that ulSize is less than 64K (on Win16 only) and that
* lpBufOrig was allocated with MAPIAllocateBuffer.
*
* Returns:
* sc Indicating error if any (see below)
*
* Side effects:
* None
*
* Errors:
* MAPI_E_INSUFFICIENT_MEMORY Allocation failed.
* MAPI_E_INVALID_PARAMETER Second or third argument is invalid.
* MAPI_E_INVALID_PARAMETER ulSize is out of range (>= 65535).
*/
STDMETHODIMP_(SCODE)
MAPIAllocateMoreExt(int heapid, ULONG ulSize, LPVOID lpv, LPVOID * lppv)
{
SCODE sc = S_OK;
LPBufInternal lpBufInt;
LPBufInternal lpBufOrig;
HLH hlh;
lpBufOrig = LPBufIntFromLPBufExt(lpv);
// Don't allow allocation to wrap across 32 bits, or to be
// greater than 64K under win16.
if ( ulSize > INT_SIZE (ulSize)
#ifdef WIN16
|| (INT_SIZE(ulSize) >= 0x10000)
#endif
)
{
DebugTrace(TEXT("MAPIAllocateMore: ulSize %ld is way too big\n"), ulSize);
sc = MAPI_E_NOT_ENOUGH_MEMORY;
goto ret;
}
#ifdef DEBUG
//$ BUG Difference in behavior between DEBUG and SHIP:
// this validation will cause the call to fail in DEBUG if the
// tail of a chain is corrupted, while the SHIP version will
// add the new block at the (valid) head without checking.
if (!FValidAllocChain(lpBufOrig))
{
sc = MAPI_E_INVALID_PARAMETER;
goto ret;
}
#endif
if (sc = ScGetHlh(heapid, &hlh))
goto ret;
// Allocate the chained block and hook it to the head of the chain.
// In DEBUG, a separately wrapped allocator is used so that
// we report the number of chains leaked, not the number of blocks.
// In SHIP, they're the same allocator.
lpBufInt = (LPBufInternal)LH_Alloc(hlh, (UINT) INT_SIZE (ulSize));
if (lpBufInt)
{
#ifdef DEBUG
{ HLH hlhOrig;
if (!ScGetHlh(GetHeapid(lpBufOrig->ulAllocFlags), &hlhOrig))
LH_SetName1(hlh, lpBufInt, TEXT("+ %s"), LH_GetName(hlhOrig, lpBufOrig));
}
#endif
// Serialize the smallest possible code section
#ifdef DEBUG
lpBufInt->hHeap = hlh;
#endif
lpBufInt->ulAllocFlags = ALLOC_WITH_ALLOC_MORE | heapid;
EnterCriticalSection(&csHeap);
lpBufInt->pLink = lpBufOrig->pLink;
lpBufOrig->pLink = lpBufInt;
LeaveCriticalSection(&csHeap);
*lppv = (LPVOID) LPBufExtFromLPBufInt(lpBufInt);
}
else
{
DebugTrace(TEXT("MAPIAllocateMore: not enough memory for %ld\n"), ulSize);
sc = MAPI_E_NOT_ENOUGH_MEMORY;
}
ret:
return sc;
}
#ifdef OLD_STUFF
/*
* MAPIReallocateBuffer
*
* Purpose:
* Allocates a memory buffer on the heap of the original allocation.
* Can be freed with MAPIFreeBuffer().
*
* Arguments:
* lpv in original pointer
* ulSize in new size, in bytes, of the buffer to be allocated.
* lppv out pointer to variable where the address of the
* allocated memory will be returned.
*
* Returns:
* sc Indicating error if any (see below)
*
* Errors:
* MAPI_E_NOT_ENOUGH_MEMORY Allocation failed.
*/
STDMETHODIMP_(SCODE)
MAPIReallocateBuffer(LPVOID lpv, ULONG ulSize, LPVOID * lppv)
{
LPBufInternal lpBufInt;
LPBufInternal lpBufIntNew;
HLH hlh;
// Do a real allocation if NULL is passed in as the base
//
if (!lpv)
return MAPIAllocateBuffer (ulSize, lppv);
// Don't allow allocation to wrap across 32 bits, or to exceed 64K
// under win16.
//
if (ulSize > INT_SIZE (ulSize)
#ifdef WIN16
|| (INT_SIZE(ulSize) >= 0x10000)
#endif
)
{
DebugTrace(TEXT("MAPIReallocateBuffer: ulSize %ld is way too big\n"), ulSize);
return MAPI_E_NOT_ENOUGH_MEMORY;
}
lpBufInt = LPBufIntFromLPBufExt (lpv);
if (ScGetHlh(GetHeapid(lpBufInt->ulAllocFlags), &hlh))
{
DebugTrace(TEXT("MAPIReallocateBuffer: playing in a heap that's gone\n"));
return MAPI_E_NOT_INITIALIZED;
}
Assert(hlh == lpBufInt->hHeap);
if ((lpBufInt->ulAllocFlags & ALLOC_WITH_ALLOC) != ALLOC_WITH_ALLOC)
return MAPI_E_INVALID_PARAMETER;
lpBufIntNew = (LPBufInternal)LH_Realloc (hlh, lpBufInt, (UINT) INT_SIZE(ulSize));
if (lpBufIntNew)
{
Assert (lpBufIntNew->hHeap == hlh);
*lppv = (LPVOID) LPBufExtFromLPBufInt (lpBufIntNew);
}
else
{
DebugTrace ( TEXT("MAPIReallocateBuffer: not enough memory for %ld\n"), ulSize);
return MAPI_E_NOT_ENOUGH_MEMORY;
}
return S_OK;
}
#endif // OLD_STUFF
#ifdef _WIN64
void WabValidateClientheap()
{
LPINSTUTIL pinstUtil;
pinstUtil = (LPINSTUTIL) PvGetInstanceGlobalsEx(lpInstUtil);
Assert(pinstUtil);
Assert(HeapValidate(pinstUtil->hlhClient->_hlhBlks, 0, NULL));
Assert(HeapValidate(pinstUtil->hlhClient->_hlhData, 0, NULL));
}
#endif
/*
- ScGetHlh
-
* Purpose:
* Finds the heap handle for a given heap ID.
*
* Arguments:
* heapid in identifies the heap
* Currently supports two: heapidClient and
* heapidProvider.
* hlh out the desired handle
*
* Returns:
* SCODE
*
* Errors:
* MAPI_E_NOT_INITIALIZED if the instance data that's supposed to
* know about the heap is unavailable.
*/
SCODE
ScGetHlh(int heapid, HLH FAR *phlh)
{
LPINSTUTIL pinstUtil;
LPINST pinst;
switch (heapid)
{
case heapidClient:
pinstUtil = (LPINSTUTIL) PvGetInstanceGlobalsEx(lpInstUtil);
if (pinstUtil)
{
Assert(pinstUtil->hlhClient);
#ifdef _WIN64 // additional check for Win64 (YST)
Assert(HeapValidate(pinstUtil->hlhClient->_hlhBlks, 0, NULL));
Assert(HeapValidate(pinstUtil->hlhClient->_hlhData, 0, NULL));
#endif
*phlh = pinstUtil->hlhClient;
return S_OK;
}
else
{
DebugTrace(TEXT("ScGetHlh: INSTUTIL not available\n"));
return MAPI_E_NOT_INITIALIZED;
}
break;
case heapidProvider:
// Note: do not acquire the INST critical section.
// That frequently leads to deadlocks. We use our own
// critical section specifically to protect the heaps.
pinst = (LPINST) PvGetInstanceGlobals();
if (pinst && pinst->cRef)
{
Assert(pinst->hlhProvider);
#ifdef _WIN64 // additional check for Win64 (YST)
Assert(HeapValidate(pinst->hlhProvider->_hlhBlks, 0, NULL));
#endif
*phlh = pinst->hlhProvider;
return S_OK;
}
else
{
DebugTrace(TEXT("ScGetHlh: INST not available\n"));
return MAPI_E_NOT_INITIALIZED;
}
break;
}
TrapSz1( TEXT("HlhOfHeapid: unknown heap ID %d"), heapid);
return MAPI_E_CALL_FAILED;
}
#ifdef DEBUG
/*
* This function validates a block of memory, and any blocks
* linked to it.
*
* NOTE: This is DEBUG-only code. To prevent differences in behavior
* between debug and retail builds, any conditions that are not
* checked in the retail code should only be asserted here -- they
* should not cause a FALSE return. Currently the retail code does
* not validate with DidAlloc(); it simply checks for accessibility
* of the memory and the correct flag values.
*
* Whether this function generates asserts or debug trace output
* is governed by a flag read from WABDBG.INI.
*/
BOOL
FValidAllocChain(LPBufInternal lpBuf)
{
LPBufInternal lpBufTemp;
if (IsBadWritePtr(lpBuf, sizeof(BufInternal)))
{
TellBadBlockInt(lpBuf, TEXT("fails address check"));
return FALSE;
}
if (GetFlags(lpBuf->ulAllocFlags) != ALLOC_WITH_ALLOC)
{
TellBadBlockInt(lpBuf, TEXT("has invalid flags"));
return FALSE;
}
for (lpBufTemp = lpBuf->pLink; lpBufTemp; lpBufTemp = lpBufTemp->pLink)
{
if (IsBadWritePtr(lpBufTemp, sizeof(BufInternal)))
{
TellBadBlockInt(lpBufTemp, TEXT("(linked block) fails address check"));
return FALSE;
}
if (GetFlags(lpBufTemp->ulAllocFlags) != ALLOC_WITH_ALLOC_MORE)
{
TellBadBlockInt(lpBufTemp, TEXT("(linked block) has invalid flags"));
return FALSE;
}
}
return TRUE;
}
#endif // DEBUG