接着往下走看看_heap_alloc_base这个函数
#define MAX_ALLOC_DATA_SIZE 0x3f8
#define BYTES_PER_PARA 16
size_t __sbh_threshold = MAX_ALLOC_DATA_SIZE;
void * __cdecl _heap_alloc_base (size_t size)
{
#ifdef WINHEAP
void * pvReturn;
#else /* WINHEAP */
_PBLKDESC pdesc;
_PBLKDESC pdesc2;
#endif /* WINHEAP */
#ifdef WINHEAP
if (size <= __sbh_threshold)
{
_mlock(_HEAP_LOCK);
pvReturn = __sbh_alloc_block(size);
_munlock(_HEAP_LOCK);
if (pvReturn)
return pvReturn;
}
if (size == 0)
size = 1;
size = (size + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1);
return HeapAlloc(_crtheap, 0, size);
}
我们可以看出,如果请求分配的内存大小小等于__sbh_threshold (默认值是0x3f8)的话,则调用__sbh_alloc_block去获得地址,如果大于的话则调用HeapAlloc去分配,其中__sbh_threshold值也是可以设置得,但必需是小于0x3f8的。
int __cdecl _set_sbh_threshold (size_t threshold)
{
// test against maximum value - if too large, return error
if (threshold > MAX_ALLOC_DATA_SIZE)
return 0;
// set the threshold value
__sbh_threshold = threshold;
return 1;
}
我们还可以看出如果大小为0的话,会设置size = 1,也就是说如果我们去new一个大小为0的地址也会成功,会自动把它大小设置为1.当然还有一些别的附加内容。
对HeapAlloc的分析不再继续往下进行,因为我找不到它的源代码。我们接着看调用__sbh_alloc_block如何分配。
typedef unsigned int BITVEC;
typedef struct tagRegion
{
int indGroupUse;
char cntRegionSize[64];
BITVEC bitvGroupHi[GROUPS_PER_REGION];
BITVEC bitvGroupLo[GROUPS_PER_REGION];
struct tagGroup grpHeadList[GROUPS_PER_REGION];
}
REGION, *PREGION;
typedef struct tagHeader
{
BITVEC bitvEntryHi;
BITVEC bitvEntryLo;
BITVEC bitvCommit;
void * pHeapData;
struct tagRegion * pRegion;
}
HEADER, *PHEADER;
PHEADER __sbh_pHeaderList; // pointer to list start
PHEADER __sbh_pHeaderScan; // pointer to list rover
int __sbh_sizeHeaderList; // allocated size of list
int __sbh_cntHeaderList; // count of entries defined
#define BYTES_PER_PARA 16
void * __cdecl __sbh_alloc_block (int intSize)
{
PHEADER pHeaderLast = __sbh_pHeaderList + __sbh_cntHeaderList;
PHEADER pHeader;
PREGION pRegion;
PGROUP pGroup;
PENTRY pEntry;
PENTRY pHead;
BITVEC bitvEntryLo;
BITVEC bitvEntryHi;
BITVEC bitvTest;
int sizeEntry;
int indEntry;
int indGroupUse;
int sizeNewFree;
int indNewFree;
// add 8 bytes entry overhead and round up to next para size
sizeEntry = (intSize + 2 * sizeof(int) + (BYTES_PER_PARA - 1))
& ~(BYTES_PER_PARA - 1);
// determine index and mask from entry size
// Hi MSB: bit 0 size: 1 paragraph
// bit 1 2 paragraphs
// ... ...
// bit 30 31 paragraphs
// bit 31 32 paragraphs
// Lo MSB: bit 0 size: 33 paragraph
// bit 1 34 paragraphs
// ... ...
// bit 30 63 paragraphs
// bit 31 64+ paragraphs
indEntry = (sizeEntry >> 4) - 1;
if (indEntry < 32)
{
bitvEntryHi = 0xffffffffUL >> indEntry;
bitvEntryLo = 0xffffffffUL;
}
else
{
bitvEntryHi = 0;
bitvEntryLo = 0xffffffffUL >> (indEntry - 32);
}
// scan header list from rover to end for region with a free
// entry with an adequate size
pHeader = __sbh_pHeaderScan;
while (pHeader < pHeaderLast)
{
if ((bitvEntryHi & pHeader->bitvEntryHi) |
(bitvEntryLo & pHeader->bitvEntryLo))
break;
pHeader++;
}
// if no entry, scan from list start up to the rover
if (pHeader == pHeaderLast)
{
pHeader = __sbh_pHeaderList;
while (pHeader < __sbh_pHeaderScan)
{
if ((bitvEntryHi & pHeader->bitvEntryHi) |
(bitvEntryLo & pHeader->bitvEntryLo))
break;
pHeader++;
}
// no free entry exists, scan list from rover to end
// for available groups to commit
if (pHeader == __sbh_pHeaderScan)
{
while (pHeader < pHeaderLast)
{
if (pHeader->bitvCommit)
break;
pHeader++;
}
// if no available groups, scan from start to rover
if (pHeader == pHeaderLast)
{
pHeader = __sbh_pHeaderList;
while (pHeader < __sbh_pHeaderScan)
{
if (pHeader->bitvCommit)
break;
pHeader++;
}
// if no available groups, create a new region
if (pHeader == __sbh_pHeaderScan)
if (!(pHeader = __sbh_alloc_new_region()))
return NULL;
}
// commit a new group in region associated with pHeader
if ((pHeader->pRegion->indGroupUse =
__sbh_alloc_new_group(pHeader)) == -1)
return NULL;
}
}
__sbh_pHeaderScan = pHeader;
pRegion = pHeader->pRegion;
indGroupUse = pRegion->indGroupUse;
// determine the group to allocate from
if (indGroupUse == -1 ||
!((bitvEntryHi & pRegion->bitvGroupHi[indGroupUse]) |
(bitvEntryLo & pRegion->bitvGroupLo[indGroupUse])))
{
// preferred group could not allocate entry, so
// scan through all defined vectors
indGroupUse = 0;
while (!((bitvEntryHi & pRegion->bitvGroupHi[indGroupUse]) |
(bitvEntryLo & pRegion->bitvGroupLo[indGroupUse])))
indGroupUse++;
}
pGroup = &pRegion->grpHeadList[indGroupUse];
// determine bucket index
indEntry = 0;
// get high entry intersection - if zero, use the lower one
if (!(bitvTest = bitvEntryHi & pRegion->bitvGroupHi[indGroupUse]))
{
indEntry = 32;
bitvTest = bitvEntryLo & pRegion->bitvGroupLo[indGroupUse];
}
while ((int)bitvTest >= 0)
{
bitvTest <<= 1;
indEntry++;
}
pEntry = pGroup->listHead[indEntry].pEntryNext;
// compute size and bucket index of new free entry
// for zero-sized entry, the index is -1
sizeNewFree = pEntry->sizeFront - sizeEntry;
indNewFree = (sizeNewFree >> 4) - 1;
if (indNewFree > 63)
indNewFree = 63;
// only modify entry pointers if bucket index changed
if (indNewFree != indEntry)
{
// test entry is sole member of bucket (next == prev),
if (pEntry->pEntryNext == pEntry->pEntryPrev)
{
// clear bit in group vector, decrement region count
// if region count is now zero, clear bit in region vector
if (indEntry < 32)
{
pRegion->bitvGroupHi[indGroupUse] &=
~(0x80000000L >> indEntry);
if (--pRegion->cntRegionSize[indEntry] == 0)
pHeader->bitvEntryHi &= ~(0x80000000L >> indEntry);
}
else
{
pRegion->bitvGroupLo[indGroupUse] &=
~(0x80000000L >> (indEntry - 32));
if (--pRegion->cntRegionSize[indEntry] == 0)
pHeader->bitvEntryLo &= ~(0x80000000L >> (indEntry - 32));
}
}
// unlink entry from list
pEntry->pEntryPrev->pEntryNext = pEntry->pEntryNext;
pEntry->pEntryNext->pEntryPrev = pEntry->pEntryPrev;
// if free entry size is still nonzero, reconnect it
if (sizeNewFree != 0)
{
// add entry to the start of the bucket list
pHead = (PENTRY)((char *)&pGroup->listHead[indNewFree] -
sizeof(int));
pEntry->pEntryNext = pHead->pEntryNext;
pEntry->pEntryPrev = pHead;
pHead->pEntryNext = pEntry;
pEntry->pEntryNext->pEntryPrev = pEntry;
// test entry is sole member of bucket (next == prev),
if (pEntry->pEntryNext == pEntry->pEntryPrev)
{
// if region count was zero, set bit in region vector
// set bit in group vector, increment region count
if (indNewFree < 32)
{
if (pRegion->cntRegionSize[indNewFree]++ == 0)
pHeader->bitvEntryHi |= 0x80000000L >> indNewFree;
pRegion->bitvGroupHi[indGroupUse] |=
0x80000000L >> indNewFree;
}
else
{
if (pRegion->cntRegionSize[indNewFree]++ == 0)
pHeader->bitvEntryLo |=
0x80000000L >> (indNewFree - 32);
pRegion->bitvGroupLo[indGroupUse] |=
0x80000000L >> (indNewFree - 32);
}
}
}
}
// change size of free entry (front and back)
if (sizeNewFree != 0)
{
pEntry->sizeFront = sizeNewFree;
((PENTRYEND)((char *)pEntry + sizeNewFree -
sizeof(ENTRYEND)))->sizeBack = sizeNewFree;
}
// mark the allocated entry
pEntry = (PENTRY)((char *)pEntry + sizeNewFree);
pEntry->sizeFront = sizeEntry + 1;
((PENTRYEND)((char *)pEntry + sizeEntry -
sizeof(ENTRYEND)))->sizeBack = sizeEntry + 1;
// one more allocation in group - test if group was empty
if (pGroup->cntEntries++ == 0)
{
// if allocating into deferred group, cancel deferral
if (pHeader == __sbh_pHeaderDefer &&
indGroupUse == __sbh_indGroupDefer)
__sbh_pHeaderDefer = NULL;
}
pRegion->indGroupUse = indGroupUse;
return (void *)((char *)pEntry + sizeof(int));
}
这个函数使用了一些全局变量需要注意一下,比如使用了__sbh_pHeaderList等,它们的值是什么时候初始化的呢?