Leaked source code of windows server 2003
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.
 
 
 
 
 
 

995 lines
24 KiB

//
// smblock.cpp
//
#include "private.h"
#include "globals.h"
#include "marshal.h"
#include "smblock.h"
#include "osver.h"
#define MAXHEAPSIZE 0x00080000
#define INITIALHEAPSIZE 0x00002000
#define RESETHEAPSIZE 0x00008000
const char c_szShared[] = "MSCTF.Shared.";
//////////////////////////////////////////////////////////////////////////////
//
// func
//
//////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------
//
// EnsureSharedHeap
//
//--------------------------------------------------------------------------
CSharedHeap *EnsureSharedHeap(SYSTHREAD *psfn)
{
Assert(psfn);
if (psfn->psheap)
return psfn->psheap;
DWORD dwThread = GetCurrentThreadId();
psfn->psheap = new CSharedHeap(dwThread);
if (!psfn->psheap)
return NULL;
if (FAILED(psfn->psheap->Init(NULL, INITIALHEAPSIZE, MAXHEAPSIZE)))
{
delete psfn->psheap;
psfn->psheap = NULL;
}
return psfn->psheap;
}
//--------------------------------------------------------------------------
//
// DestroySharedHeap
//
//--------------------------------------------------------------------------
void DestroySharedHeap(SYSTHREAD *psfn)
{
Assert(psfn);
if (!psfn->psheap)
return;
delete psfn->psheap;
psfn->psheap = NULL;
}
//--------------------------------------------------------------------------
//
// EnsureSharedBlockForThread
//
//--------------------------------------------------------------------------
#define MAX_THREAD_NUM 15
CSharedBlock *EnsureSharedBlockForThread(SYSTHREAD *psfn, DWORD dwThreadId)
{
int nCnt;
int i;
CSharedBlock *psb = NULL;
Assert(psfn);
if (!psfn->prgThreadMem)
psfn->prgThreadMem = new CPtrArray<CSharedBlock>;
if (!psfn->prgThreadMem)
return NULL;
nCnt = psfn->prgThreadMem->Count();
for (i = 0; i < nCnt; i++)
{
psb = psfn->prgThreadMem->Get(i);
if (psb->GetThreadId() == dwThreadId)
{
//
// this thread mem was found in the 2nd half of this list.
// we don't have to reorder this entry.
//
if (nCnt < (MAX_THREAD_NUM) / 2 || (i >= (nCnt / 2)))
goto Exit;
//
// reorder this entry.
//
psfn->prgThreadMem->Remove(i,1);
goto SetPSB;
}
}
#ifndef _WIN64
if (!IsOnNT())
psb = new CSharedBlock9x(c_szShared, dwThreadId);
else
#endif
psb = new CSharedBlockNT(c_szShared, dwThreadId, FALSE);
if (!psb)
return NULL;
if (FAILED(psb->Init(NULL, 0, 0, NULL, FALSE)))
{
delete psb;
return NULL;
}
SetPSB:
if (psfn->prgThreadMem->Count() >= MAX_THREAD_NUM)
{
//
// delete the oldest thread mem entry.
//
CSharedBlock *psbTemp = psfn->prgThreadMem->Get(0);
psfn->prgThreadMem->Remove(0, 1);
delete psbTemp;
}
CSharedBlock **ppsb = psfn->prgThreadMem->Append(1);
if (!ppsb)
{
delete psb;
return NULL;
}
*ppsb = psb;
Exit:
return psb;
}
//--------------------------------------------------------------------------
//
// DestroySharedBlocks
//
//--------------------------------------------------------------------------
void DestroySharedBlocks(SYSTHREAD *psfn)
{
int nCnt;
int i;
CSharedBlock *psb = NULL;
Assert(psfn);
if (!psfn->prgThreadMem)
return;
nCnt = psfn->prgThreadMem->Count();
for (i = 0; i < nCnt; i++)
{
psb = psfn->prgThreadMem->Get(i);
delete psb;
}
delete psfn->prgThreadMem;
psfn->prgThreadMem = NULL;
return;
}
//////////////////////////////////////////////////////////////////////////////
//
// CSharedBlockNT
//
//////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------
//
// ctor
//
//--------------------------------------------------------------------------
CSharedBlockNT::CSharedBlockNT(const char *pszPrefix, DWORD dwThread, BOOL fUseUniqueName) : CSharedBlock(pszPrefix, dwThread)
{
_fUseUniqueName = fUseUniqueName;
}
//--------------------------------------------------------------------------
//
// dtor
//
//--------------------------------------------------------------------------
CSharedBlockNT::~CSharedBlockNT()
{
if (_pvBase)
UnmapViewOfFile(_pvBase);
if (_hfm)
CloseHandle(_hfm);
TraceMsg(TF_GENERAL, "CSharedBlock dtor");
TraceMsg(TF_GENERAL, " _dwThread 0x%08x", _dwThread);
TraceMsg(TF_GENERAL, " _ulInitCommitSize 0x%08x", _ulInitCommitSize);
TraceMsg(TF_GENERAL, " _ulCommitSize 0x%08x", _ulCommitSize);
}
//--------------------------------------------------------------------------
//
// Init
//
//--------------------------------------------------------------------------
HRESULT CSharedBlockNT::Init(SECURITY_DESCRIPTOR *pSecDes,
ULONG ulSize,
ULONG ulCommitSize,
void *pvBase,
BOOL fCreate,
BOOL *pfAlreadyExists)
{
char szName[MAX_PATH];
char szObjName[MAX_PATH];
StringCopyArray(szName, _pszPrefix);
int nLen = lstrlen(szName);
if (!SetName(&szName[nLen], ARRAYSIZE(szName) - nLen, SZSHAREDMUTEX, _dwThread))
return E_FAIL;
if (_fUseUniqueName)
{
GetDesktopUniqueNameArray(szName, szObjName);
}
else
StringCchCopy(szObjName, ARRAYSIZE(szObjName), szName);
CCicSecAttr sa;
if (!_mutex.Init(sa, szObjName))
return E_FAIL;
if (!SetName(&szName[nLen], ARRAYSIZE(szName) - nLen, SZSHAREDFILEMAP, _dwThread))
return E_FAIL;
if (_fUseUniqueName)
{
GetDesktopUniqueNameArray(szName, szObjName);
}
else
StringCchCopy(szObjName, ARRAYSIZE(szObjName), szName);
if (fCreate)
{
CCicSecAttr saFileMapping;
_hfm = CreateFileMapping(INVALID_HANDLE_VALUE,
saFileMapping,
PAGE_READWRITE | SEC_RESERVE,
0,
ulSize,
szObjName);
if (pfAlreadyExists != NULL)
{
*pfAlreadyExists = (GetLastError() == ERROR_ALREADY_EXISTS);
}
}
else
{
_hfm = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szObjName);
if (pfAlreadyExists != NULL)
{
*pfAlreadyExists = _hfm ? TRUE : FALSE;
}
}
if (_hfm == NULL)
{
TraceMsg(TF_GENERAL, "CSharedBlock Init: Open/CreateFileMapping failed");
Assert(!fCreate);
return E_OUTOFMEMORY;
}
_pvBase = (void *)MapViewOfFile(_hfm,
FILE_MAP_WRITE,
0,
0,
0);
if (!_pvBase)
{
TraceMsg(TF_GENERAL, "CSharedBlock Init: MapVieOfFile failed");
return E_OUTOFMEMORY;
}
if (fCreate)
{
void *pvResult;
pvResult = VirtualAlloc(_pvBase,
ulCommitSize,
MEM_COMMIT,
PAGE_READWRITE);
if (!pvResult)
{
TraceMsg(TF_GENERAL, "CSharedBlock Init: VirtualAlloc failed");
CloseHandle(_hfm);
_hfm = NULL;
return E_OUTOFMEMORY;
}
}
_ulCommitSize = ulCommitSize;
_ulInitCommitSize = ulCommitSize;
return S_OK;
}
//--------------------------------------------------------------------------
//
// GetPtrFromBlockId
//
//--------------------------------------------------------------------------
void *CSharedBlockNT::GetPtrFromBlockId(ULONG ulBlockId)
{
if (((CSharedHeap::HEAPHDR *)_pvBase)->ulSize <= ulBlockId)
{
Assert(0);
return NULL;
}
return GetPtr(ulBlockId);
}
//--------------------------------------------------------------------------
//
// Commit
//
//--------------------------------------------------------------------------
HRESULT CSharedBlockNT::Commit(ULONG ulNewSize)
{
void *pv;
Assert(ulNewSize >= _ulCommitSize);
if (ulNewSize == _ulCommitSize)
return S_OK;
pv = VirtualAlloc(_pvBase, ulNewSize, MEM_COMMIT, PAGE_READWRITE);
if (!pv)
{
TraceMsg(TF_GENERAL, "CSharedBlock Commit: VirtualAlloc failed");
return E_OUTOFMEMORY;
}
_ulCommitSize = ulNewSize;
return S_OK;
}
//--------------------------------------------------------------------------
//
// Reset
//
//--------------------------------------------------------------------------
HRESULT CSharedBlockNT::Reset()
{
void *pv;
Assert(_ulCommitSize >= _ulInitCommitSize);
if (_ulCommitSize == _ulInitCommitSize)
return S_FALSE;
VirtualFree(_pvBase, _ulCommitSize, MEM_DECOMMIT);
pv = VirtualAlloc(_pvBase, _ulInitCommitSize, MEM_COMMIT, PAGE_READWRITE);
if (!pv)
{
TraceMsg(TF_GENERAL, "CSharedBlock Reset: VirtualAlloc failed");
return E_OUTOFMEMORY;
}
TraceMsg(TF_GENERAL, "CSharedBlock Reset");
TraceMsg(TF_GENERAL, " Old _ulCommitSize 0x%08x", _ulCommitSize);
TraceMsg(TF_GENERAL, " New _ulCommitSize 0x%08x", _ulInitCommitSize);
_ulCommitSize = _ulInitCommitSize;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
// CSharedBlock9x
//
//////////////////////////////////////////////////////////////////////////////
#ifndef _WIN64
//--------------------------------------------------------------------------
//
// ctor
//
//--------------------------------------------------------------------------
CSharedBlock9x::CSharedBlock9x(const char *pszPrefix, DWORD dwThread) : CSharedBlock(pszPrefix, dwThread)
{
_hsheap = NULL;
}
//--------------------------------------------------------------------------
//
// dtor
//
//--------------------------------------------------------------------------
CSharedBlock9x::~CSharedBlock9x()
{
if (_pvBase)
HeapFree(_hsheap, 0, _pvBase);
if (_hsheap)
HeapDestroy(_hsheap);
TraceMsg(TF_GENERAL, "CSharedBlock 9x dtor");
TraceMsg(TF_GENERAL, " _dwThread 0x%08x", _dwThread);
TraceMsg(TF_GENERAL, " _ulInitCommitSize 0x%08x", _ulInitCommitSize);
TraceMsg(TF_GENERAL, " _ulCommitSize 0x%08x", _ulCommitSize);
}
//--------------------------------------------------------------------------
//
// Init
//
//--------------------------------------------------------------------------
HRESULT CSharedBlock9x::Init(SECURITY_DESCRIPTOR *pSecDes,
ULONG ulSize,
ULONG ulCommitSize,
void *pvBase,
BOOL fCreate,
BOOL *pfAlreadyExists)
{
char szName[MAX_PATH];
StringCopyArray(szName, _pszPrefix);
UINT uLen = lstrlen(szName);
if (!SetName(&szName[uLen], ARRAYSIZE(szName) - uLen, SZSHAREDMUTEX, _dwThread))
return E_FAIL;
CCicSecAttr sa;
if (!_mutex.Init(sa, szName))
return E_FAIL;
if (fCreate)
{
_hsheap = HeapCreate(0x04000000, ulCommitSize + 0x100, 0);
if ( _hsheap == NULL )
return E_FAIL;
_pvBase = HeapAlloc(_hsheap, 0, ulCommitSize);
if (pfAlreadyExists != NULL)
{
*pfAlreadyExists = TRUE;
}
}
else
{
_hsheap = NULL;
_pvBase = NULL;
if (pfAlreadyExists != NULL)
{
*pfAlreadyExists = FALSE;
}
}
_ulCommitSize = ulCommitSize;
_ulInitCommitSize = ulCommitSize;
return S_OK;
}
//--------------------------------------------------------------------------
//
// Commit
//
//--------------------------------------------------------------------------
HRESULT CSharedBlock9x::Commit(ULONG ulNewSize)
{
void *pvNew;
pvNew = HeapReAlloc(_hsheap, 0, _pvBase, ulNewSize);
if (!pvNew)
{
HeapFree(_hsheap, 0, _pvBase);
_pvBase = NULL;
return E_OUTOFMEMORY;
}
TraceMsg(TF_GENERAL, "Commit 0x%08x", ulNewSize);
_pvBase = pvNew;
_ulCommitSize = ulNewSize;
return S_OK;
}
//--------------------------------------------------------------------------
//
// Reset
//
//--------------------------------------------------------------------------
HRESULT CSharedBlock9x::Reset()
{
Assert(_ulCommitSize >= _ulInitCommitSize);
if (_ulCommitSize == _ulInitCommitSize)
return S_FALSE;
HeapFree(_hsheap, 0, _pvBase);
_pvBase = HeapAlloc(_hsheap, 0, _ulInitCommitSize);
if (!_pvBase)
return E_OUTOFMEMORY;
_ulCommitSize = _ulInitCommitSize;
return S_OK;
}
#endif // !_WIN64
//////////////////////////////////////////////////////////////////////////////
//
// CSharedHeap
//
//////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------
//
// ctor
//
//--------------------------------------------------------------------------
CSharedHeap::CSharedHeap(DWORD dwThread)
{
_dwThread = dwThread;
_psb = NULL;
}
//--------------------------------------------------------------------------
//
// dtor
//
//--------------------------------------------------------------------------
CSharedHeap::~CSharedHeap()
{
#ifdef DEBUG
if (_psb->GetBase())
{
HEAPHDR *phhdr = (HEAPHDR *)_psb->GetPtr(0);
BLOCKHDR *pbhdr = (BLOCKHDR *)_psb->GetPtr(phhdr->ulList);
Assert(pbhdr->IsFree());
Assert(pbhdr->ulNext == (-1));
}
#endif
if (_psb)
delete _psb;
}
//--------------------------------------------------------------------------
//
// Init
//
//--------------------------------------------------------------------------
HRESULT CSharedHeap::Init(SECURITY_DESCRIPTOR *pSecDes,
ULONG ulInitSize,
ULONG ulMaxSize)
{
HRESULT hr;
#ifndef _WIN64
if (!IsOnNT())
_psb = new CSharedBlock9x(c_szShared, _dwThread);
else
#endif
_psb = new CSharedBlockNT(c_szShared, _dwThread, FALSE);
if (!_psb)
return E_OUTOFMEMORY;
hr = _psb->Init(pSecDes, ulMaxSize, ulInitSize, NULL, TRUE);
if (FAILED(hr))
return E_FAIL;
InitHeap(ulInitSize);
return S_OK;
}
//--------------------------------------------------------------------------
//
// InitHeap
//
//--------------------------------------------------------------------------
void CSharedHeap::InitHeap(ULONG ulInitSize)
{
BYTE *pb;
HEAPHDR *phhdr;
BLOCKHDR *pbhdr;
//
// init heap header.
//
pb = (BYTE *)_psb->GetPtr(0);
phhdr = (HEAPHDR *)pb;
phhdr->ulList = _psb->GetOffset(pb + sizeof(HEAPHDR));
phhdr->ulSize = ulInitSize;
//
// init first block
//
pb = (BYTE *)_psb->GetPtr(phhdr->ulList);
pbhdr = (BLOCKHDR *)pb;
pbhdr->ulPrev = 0;
pbhdr->ulNext = -1;
pbhdr->SetFree(TRUE);
pbhdr->SetSize(ulInitSize - _psb->GetOffset(pb + sizeof(BLOCKHDR)) & ~0x1f);
_dbg_HeapCheck();
}
//--------------------------------------------------------------------------
//
// Alloc
//
//--------------------------------------------------------------------------
void *CSharedHeap::Alloc(ULONG ulSize)
{
BYTE *pb;
HEAPHDR *phhdr;
BLOCKHDR *pbhdr = NULL;
ULONG ulCur;
BOOL fFound = FALSE;
BOOL fHeapIncreased = FALSE;
void *pvRet = NULL;
if (!GetBlock()->GetMutex()->Enter())
return NULL;
_dbg_HeapCheck();
ulSize += 0x0000001F;
ulSize &= (ULONG)(-0x20);
pb = (BYTE *)_psb->GetPtr(0);
phhdr = (HEAPHDR *)pb;
TryAgain:
ulCur = phhdr->ulList;
while (ulCur != -1)
{
pbhdr = (BLOCKHDR *)_psb->GetPtr(ulCur);
if (pbhdr->IsFree() && (pbhdr->GetSize() >= ulSize))
{
fFound = TRUE;
break;
}
ulCur = pbhdr->ulNext;
}
if (!fFound)
{
if (!pbhdr)
{
pvRet = NULL;
goto Exit;
}
Assert(pbhdr->ulNext == (-1));
if (fHeapIncreased)
{
pvRet = NULL;
goto Exit;
}
if (FAILED(_psb->Commit(_psb->GetCommitSize() + ulSize)))
{
pvRet = NULL;
goto Exit;
}
phhdr->ulSize += ulSize;
pbhdr->SetSize(pbhdr->GetSize() + ulSize);
fHeapIncreased = TRUE;
goto TryAgain;
}
Assert(pbhdr->GetSize() >= ulSize);
if (pbhdr->GetSize() < (ulSize + 32 + sizeof(BLOCKHDR)))
{
pbhdr->SetFree(FALSE);
}
else
{
pbhdr->SetFree(FALSE);
pbhdr->SetSize(ulSize);
BLOCKHDR *pbhdrNext = (BLOCKHDR *)((BYTE *)pbhdr->GetPtr() + ulSize);
pbhdrNext->ulNext = pbhdr->ulNext;
pbhdrNext->ulPrev = _psb->GetOffset(pbhdr);
pbhdr->ulNext = _psb->GetOffset(pbhdrNext);
ULONG ulNewSize;
if (pbhdrNext->ulNext != (-1))
ulNewSize = pbhdrNext->ulNext - pbhdr->ulNext - sizeof(BLOCKHDR);
else
ulNewSize = (_psb->GetCommitSize() -
_psb->GetOffset((BYTE*)pbhdrNext + sizeof(BLOCKHDR))) & ~0x1f;
pbhdrNext->SetSize(ulNewSize);
pbhdrNext->SetFree(TRUE);
BLOCKHDR *pbhdrNextNext = (BLOCKHDR *)((BYTE *)pbhdrNext->GetPtr() + ulNewSize);
pbhdrNextNext->ulPrev = _psb->GetOffset(pbhdrNext);
}
_dbg_HeapCheck();
pvRet = pbhdr->GetPtr();
Exit:
GetBlock()->GetMutex()->Leave();
return pvRet;
}
//--------------------------------------------------------------------------
//
// Realloc
//
//--------------------------------------------------------------------------
#ifdef LATER
void *CSharedHeap::Realloc(void *pv, ULONG ulSize)
{
if (!_psb->IsValidPtr(pv))
{
Assert(0);
return NULL;
}
if (!GetBlock()->GetMutex()->Enter())
return NULL;
void *pvRet = NULL;
BLOCKHDR *pbhdr = (BLOCKHDR *)((BYTE *)pv - sizeof(BLOCKHDR));
if (pbhdr->GetSize() >= ulSize)
{
pvRet = pv;
goto Exit;
}
//
// perf: This should be smart!!
//
pvRet = Alloc(ulSize);
if (pvRet)
{
memcpy(pvRet, pv, pbhdr->GetSize());
}
Free(pv);
Exit:
GetBlock()->GetMutex()->Leave();
return pvRet;
}
#endif
//--------------------------------------------------------------------------
//
// Free
//
//--------------------------------------------------------------------------
BOOL CSharedHeap::Free(void *pv)
{
if (!_psb->IsValidPtr(pv))
{
Assert(0);
return FALSE;
}
if (!GetBlock()->GetMutex()->Enter())
return FALSE;
BOOL bRet = FALSE;
_dbg_HeapCheck();
HEAPHDR *phhdr;
BLOCKHDR *pbhdr = (BLOCKHDR *)((BYTE *)pv - sizeof(BLOCKHDR));
//
// do nothing for free block.
//
if (pbhdr->IsFree())
{
Assert(0);
goto Exit;
}
pbhdr->SetFree(TRUE);
MergeFreeBlock(pbhdr);
if (pbhdr->ulPrev)
{
BLOCKHDR *pbhdrPrev = (BLOCKHDR *)_psb->GetPtr(pbhdr->ulPrev);
if (pbhdrPrev->IsFree())
MergeFreeBlock(pbhdrPrev);
}
//
// if we don't have any mem block, it is time to recommit the block.
//
phhdr = (HEAPHDR *)_psb->GetPtr(0);
pbhdr = (BLOCKHDR *)_psb->GetPtr(phhdr->ulList);
if (pbhdr->ulNext == (-1))
{
if (_psb->GetCommitSize() > RESETHEAPSIZE)
{
HRESULT hr = _psb->Reset();
if (FAILED(hr))
{
Assert(0);
goto Exit;
}
if (hr == S_OK)
InitHeap(_psb->GetInitCommitSize());
}
}
bRet = TRUE;
Exit:
_dbg_HeapCheck();
GetBlock()->GetMutex()->Leave();
return bRet;
}
//--------------------------------------------------------------------------
//
// MergeFreeBlock
//
//--------------------------------------------------------------------------
void CSharedHeap::MergeFreeBlock(BLOCKHDR *pbhdr)
{
BLOCKHDR *pbhdrNext = (BLOCKHDR *)_psb->GetPtr(pbhdr->ulNext);
BLOCKHDR *pbhdrNewNext = NULL;
if (pbhdrNext->IsFree())
{
ULONG ulNewSize;
pbhdr->ulNext = pbhdrNext->ulNext;
if (pbhdr->ulNext != (-1))
{
pbhdrNewNext = (BLOCKHDR *)_psb->GetPtr(pbhdr->ulNext);
// ulNewSize = pbhdrNewNext->ulNext - pbhdr->ulNext - sizeof(BLOCKHDR);
ulNewSize = ((DWORD)(DWORD_PTR)((BYTE *)pbhdrNewNext - (BYTE *)pbhdr) - sizeof(BLOCKHDR));
pbhdrNewNext->ulPrev = _psb->GetOffset(pbhdr);
}
else
{
ulNewSize = (_psb->GetCommitSize() -
_psb->GetOffset((BYTE*)pbhdrNext + sizeof(BLOCKHDR))) & ~0x1f;
}
pbhdr->SetSize(ulNewSize);
}
}
//--------------------------------------------------------------------------
//
// IsValidBlock
//
//--------------------------------------------------------------------------
BOOL CSharedHeap::IsValidBlock(CSharedBlock *psb, void *pv)
{
BOOL fFound = FALSE;
//
// On Win9x, we use system shared heap _psb does not have a pointer..
// How can we valid the block??
//
if (!IsOnNT())
return TRUE;
_try
{
BLOCKHDR *pbhdr = (BLOCKHDR *)((BYTE *)pv - sizeof(BLOCKHDR));
BYTE *pb;
HEAPHDR *phhdr;
ULONG ulCur;
pb = (BYTE *)psb->GetPtr(0);
phhdr = (HEAPHDR *)pb;
ulCur = phhdr->ulList;
while (ulCur != -1)
{
BLOCKHDR *pbhdrTmp = (BLOCKHDR *)psb->GetPtr(ulCur);
if (pbhdrTmp == pbhdr)
{
fFound = TRUE;
break;
}
ulCur = pbhdrTmp->ulNext;
}
}
_except(1)
{
Assert(0);
}
return fFound;
}
//--------------------------------------------------------------------------
//
// _dbg_HeapCheck()
//
//--------------------------------------------------------------------------
#ifdef DEBUG
void CSharedHeap::_dbg_HeapCheck()
{
HEAPHDR *phhdr = (HEAPHDR *)_psb->GetPtr(0);
BLOCKHDR *pbhdr = NULL;
BLOCKHDR *pbhdrPrev = NULL;
ULONG ulCur = phhdr->ulList;
while (ulCur != -1)
{
Assert(!(ulCur & CIC_ALIGNMENT));
pbhdr = (BLOCKHDR *)_psb->GetPtr(ulCur);
if (pbhdrPrev)
{
Assert(_psb->GetOffset(pbhdrPrev) == pbhdr->ulPrev);
Assert(_psb->GetPtr(pbhdrPrev->ulNext) == pbhdr);
Assert(pbhdrPrev->ulSize ==
((BYTE *)pbhdr - (BYTE *)pbhdrPrev - sizeof(BLOCKHDR)));
Assert(!pbhdrPrev->IsFree() || !pbhdr->IsFree());
}
else
{
Assert(!pbhdr->ulPrev);
}
pbhdrPrev = pbhdr;
ulCur = pbhdr->ulNext;
}
}
#endif