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.
903 lines
23 KiB
903 lines
23 KiB
/*
|
|
- 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
|