/* - 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 #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