Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

942 lines
15 KiB

/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker
*
* Copyright (C) Microsoft Corp 1992-95. All rights reserved.
*
* File: memory.cpp
*
* File Comments:
*
* Memory specific routines.
*
***********************************************************************/
#include "link.h"
#if DBG && (_MSC_VER >= 1000)
extern "C" void *_ReturnAddress(void);
#pragma intrinsic(_ReturnAddress)
#endif
// ilink memory manager variables
static PVOID pvHeap; // base of heap
static PVOID pvCur; // current pointer into heap
static DWORD cFree; // free space
//
// Functions
//
PVOID
AllocNewBlock (
IN size_t cb
)
/*++
Routine Description:
Allocates a new block of memory for the permanent heap. This is used
in conjunction with ALLOC_PERM().
Arguments:
cb - Count of bytes requested.
Return Value:
Pointer to memory requested
--*/
{
assert(cb < cbTotal);
#if 0
// Can't do this. The heap manager may move the partial page and we're ill-prepared to
// deal with that.
// realloc previous block
if (pch) {
PvRealloc(pch, cbTotal-cbFree);
}
#endif
// alloc a new block
pch = (BYTE *) PvAllocZ(cbTotal);
// setup values
cbFree = cbTotal - cb;
// done
return (PVOID)pch;
}
void
GrowBlk (
IN OUT PBLK pblk,
IN DWORD cbNewSize
)
/*++
Routine Description:
Grows the current block by atleast 1K or atleast twice the
previous size of the memory block.
Arguments:
pblk - pointer to a BLK.
cbNewSize - Count of bytes requested.
Return Value:
None.
--*/
{
DWORD cbNewAlloc;
if (pblk->cbAlloc >= cbNewSize) {
return;
}
// grow by atleast twice or 1K.
cbNewAlloc = __max(cbNewSize, pblk->cbAlloc * 2);
cbNewAlloc = __max(cbNewAlloc, 1024);
pblk->pb = (BYTE *) PvRealloc(pblk->pb, cbNewAlloc);
pblk->cbAlloc = cbNewAlloc;
}
// IbAppendBlkZ -- appends zeroed space to the end of the logical part of a BLK.
DWORD
IbAppendBlkZ(PBLK pblk, DWORD cbNew)
{
assert (pblk);
// if there isn't enough space, grow it.
if (pblk->cb + cbNew > pblk->cbAlloc) {
GrowBlk(pblk, pblk->cb + cbNew);
}
memset(&pblk->pb[pblk->cb], 0, cbNew);
pblk->cb += cbNew;
return pblk->cb - cbNew;
}
DWORD
IbAppendBlk (
PBLK pblk,
const void *pvNew,
DWORD cbNew
)
/*++
Routine Description:
Appends data to the end of an existing memory block.
Arguments:
pblk - pointer to existing memory block.
pvNew - pointer to memory block to be appended.
cbNew - Count of bytes to be appended.
Return Value:
None.
--*/
{
assert (pblk);
// if there isn't enough space, grow it.
if (pblk->cb + cbNew > pblk->cbAlloc) {
GrowBlk(pblk, pblk->cb + cbNew);
}
// append new data
memcpy(&pblk->pb[pblk->cb], pvNew, cbNew);
pblk->cb += cbNew;
return pblk->cb - cbNew;
}
void
FreeBlk (
IN OUT PBLK pblk
)
/*++
Routine Description:
Frees up a blk.
Arguments:
pblk - pointer to new block to be free'd.
Return Value:
None.
--*/
{
if (pblk->pb == NULL) {
return;
}
FreePv(pblk->pb);
pblk->pb = NULL;
pblk->cb = pblk->cbAlloc = 0;
}
void *
PvAllocLheap(LHEAP *plheap, DWORD cb)
{
VOID *pvReturn;
cb = (cb + 3) & ~3;
if (plheap->plheapbCur == NULL || plheap->plheapbCur->cbFree < cb) {
LHEAPB *plheapb = (LHEAPB *) PvAllocZ(__max(8192, cb) + sizeof(LHEAPB));
plheapb->cbFree = __max(8192, cb);
plheapb->plheapbNext = plheap->plheapbCur;
plheap->plheapbCur = plheapb;
}
pvReturn = &plheap->plheapbCur->rgbData[plheap->plheapbCur->cbUsed];
plheap->plheapbCur->cbUsed += cb;
plheap->plheapbCur->cbFree -= cb;
return pvReturn;
}
void
FreeLheap(LHEAP *plheap)
{
while (plheap->plheapbCur != NULL) {
LHEAPB *plheapb = plheap->plheapbCur;
plheap->plheapbCur = plheapb->plheapbNext;
FreePv(plheapb);
}
}
BOOL
FReserveMemory (
PVOID Addr,
DWORD cb,
DWORD *perr
)
/*++
Routine Description:
Reserves memory to be used for the ILK file.
Arguments:
Addr - start address of memory to reserve.
cb - size to be reserved.
perr - ptr to store any error code
Return Value:
TRUE if it succeeded in reserving the memory.
--*/
{
PVOID pvResMemBase;
assert(Addr);
assert(cb);
// reserve address space
pvResMemBase = VirtualAlloc(Addr, cb, MEM_RESERVE, PAGE_NOACCESS);
if (!pvResMemBase || pvResMemBase != Addr) {
*perr = GetLastError();
return(FALSE);
}
return(TRUE);
}
void
FreeMemory (
PVOID pvResMemBase
)
/*++
Routine Description:
Frees memory to be used for the ILK file.
Arguments:
pvResMemBase - base of reserved memory.
Return Value:
TRUE if it succeeded in freeing the memory.
--*/
{
assert(pvResMemBase);
if (!VirtualFree(pvResMemBase, 0, MEM_RELEASE)) {
Fatal(NULL, INTERNAL_ERR);
}
}
// check to see if there is enough free disk space (for chicago
// only since GetLastFatal() doesn't quite work).
BOOL
FFreeDiskSpace (
DWORD cbSpaceReqd
)
{
DWORD dwSecPerCluster, dwcbCluster, dwFreeClusters, dwClusters;
char szDrive[_MAX_DRIVE+1];
_splitpath(szIncrDbFilename, szDrive, NULL, NULL, NULL);
if (szDrive[0] != '\0') {
strcat(szDrive, "\\");
}
if (GetDiskFreeSpace(szDrive, &dwSecPerCluster, &dwcbCluster,
&dwFreeClusters, &dwClusters)) {
DWORD dwClustersRequired = cbSpaceReqd / (dwcbCluster * dwSecPerCluster);
return(dwFreeClusters > dwClustersRequired);
}
return TRUE;
}
PVOID
CreateHeap (
PVOID Addr,
DWORD cbFile,
BOOL fCreate,
DWORD *pdwErr
)
/*++
Routine Description:
Opens the ILK file map at the specified address if not already done.
Arguments:
Addr - Address to map the file to.
cbFile - size of file when fCreate is FALSE else 0
fCreate - TRUE if file is to be created.
pdwErr - ptr to error code.
Return Value:
-1 on FAILURE & Address mapped to on SUCCESS.
--*/
{
INT flags;
DWORD cbReserve;
DWORD ulAddr = (DWORD)Addr;
assert(!pvHeap);
// set the file open flags
flags = O_RDWR | O_BINARY;
if (fCreate) {
flags |= (O_CREAT | O_TRUNC);
}
// create the file map
cFree = cbFile;
FileIncrDbHandle = FileOpenMapped(szIncrDbFilename,
flags, S_IREAD | S_IWRITE, &ulAddr, &cFree, pdwErr);
// verify the open
if (-1 != FileIncrDbHandle) {
assert(Addr ? ulAddr == (DWORD)Addr : 1);
// set the current file ptr
if (fCreate) {
pvCur = (PVOID) ulAddr;
} else {
pvCur = (PVOID)(ulAddr + FileSeek(FileIncrDbHandle, 0, SEEK_END));
}
// reserve space for ILK map
cbReserve = ILKMAP_MAX - (cFree+cbFile);
if (cbReserve && !FReserveMemory((BYTE *) pvCur + cFree, cbReserve, pdwErr)) {
FileCloseMap(FileIncrDbHandle);
pvCur = pvHeap = 0; cFree = 0;
return (PVOID)-1;
}
return (pvHeap = (PVOID)ulAddr);
} else {
return (PVOID)-1;
} // end if
}
void
FreeHeap (
VOID
)
/*++
Routine Description:
Blow away the heap - closes the map & file.
Arguments:
None.
Return Value:
None.
--*/
{
// nothing to do
if (!pvHeap) {
return;
}
// free up reserved memory
if (ILKMAP_MAX > ((DWORD)pvCur - (DWORD) pvHeap + cFree)) {
FreeMemory((PVOID)((BYTE *) pvCur+cFree));
}
// simply close the map; no need to write out anything
FileCloseMap(FileIncrDbHandle);
// done
pvHeap = 0;
pvCur = 0;
cFree = 0;
}
void
CloseHeap (
VOID
)
/*++
Routine Description:
Just frees up the reserved memory & updates internal state.
Arguments:
None.
Return Value:
None.
--*/
{
// nothing to do
if (!pvHeap) {
return;
}
// free up reserved memory
if (ILKMAP_MAX > ((DWORD)pvCur - (DWORD) pvHeap + cFree)) {
FreeMemory((PVOID)((BYTE *) pvCur+cFree));
}
// set ILK file pointer
FileSeek(FileIncrDbHandle, (DWORD) pvCur - (DWORD) pvHeap, SEEK_SET);
// set ILK file size
FileSetSize(FileIncrDbHandle);
// done
pvHeap = 0;
pvCur = 0;
cFree = 0;
}
// On chicago it is possible that some other process may lock up
// memory that is about to be reserved by the linker.
void
UnableToExtendMap (
VOID
)
{
errInc = errOutOfDiskSpace; // REVIEW: value is overloaded now.
CleanUp((PPIMAGE) &pvHeap);
if (fTest) {
PostNote(NULL, UNABLETOEXTENDMAP);
}
ExitProcess(SpawnFullBuild(TRUE));
}
void
OutOfDiskSpace (
VOID
)
/*++
Routine Description:
Low on disk space. Full build if doing an ilink else non-ilink build.
Arguments:
None.
Return Value:
None.
--*/
{
if (fIncrDbFile) {
errInc = errOutOfDiskSpace;
CleanUp((PPIMAGE) &pvHeap);
PostNote(NULL, LOWSPACERELINK);
ExitProcess(SpawnFullBuild(TRUE));
} else {
errInc = errOutOfDiskSpace;
CleanUp((PPIMAGE) &pvHeap);
Warning(NULL, LOWSPACE);
ExitProcess(SpawnFullBuild(FALSE));
}
}
void
OutOfILKSpace (
VOID
)
/*++
Routine Description:
If an incremental link does a full build, else errors out.
Arguments:
None.
Return Value:
None.
--*/
{
if (fIncrDbFile) {
errInc = errOutOfMemory;
CleanUp((PPIMAGE) &pvHeap);
ExitProcess(SpawnFullBuild(TRUE));
}
Fatal(NULL, NOTENOUGHMEMFORILINK);
}
DWORD
CalcILKMapSize (
IN DWORD cb,
IN DWORD cbInUse,
IN DWORD cbCurrent
)
/*++
Routine Description:
Calculates new size of ILK map by doubling current size as many times
as needed to fulfill current request.
Arguments:
cb - bytes to be allocated.
cbInUse - current size of map in use.
cbCurrent - current size of ILK map.
Return Value:
New size of ILK map.
--*/
{
if (cb < (cbCurrent*2 - cbInUse)) {
return (cbCurrent *2);
}
return CalcILKMapSize(cb, cbInUse, cbCurrent*2);
}
void
GrowILKMap (
DWORD cb
)
/*++
Routine Description:
Checks if there is enough memory & grows the ILK map file.
Arguments:
cb - count of bytes requested
Return Value:
None.
--*/
{
DWORD cbCur = (BYTE *) pvCur - (BYTE *) pvHeap; // current size in use
DWORD cbMapSize, cbReserve;
DWORD dwErr = 0;
// calculate size of reserved memory
assert((cbCur+cFree) <= ILKMAP_MAX);
cbReserve = ILKMAP_MAX - (cbCur+cFree);
// free up reserved memory if any
if (cbReserve) {
PVOID pvResMemBase = (PVOID)((BYTE *) pvCur + cFree);
FreeMemory(pvResMemBase);
}
// check if there is enough memory
if (cb > (ILKMAP_MAX - cbCur)) {
OutOfILKSpace();
}
// figure out new size of ILK map
cbMapSize = CalcILKMapSize(cb, cbCur, cbCur+cFree);
assert(cbMapSize <= ILKMAP_MAX);
// figure out how much memory to reserve
cbReserve = ILKMAP_MAX - cbMapSize;
// reserve additional memory if any
if (cbReserve) {
DWORD err;
PVOID pvResMemBase = (PVOID)((BYTE *) pvHeap + cbMapSize);
if (!FReserveMemory(pvResMemBase, cbReserve, &err)) {
UnableToExtendMap();
}
}
// update free ILK space
cFree = cbMapSize - cbCur;
// grow ILK map to new size
if (FileSeekEx(FileIncrDbHandle, cbMapSize, SEEK_SET, &dwErr) == -1L) {
if (cbReserve) {
FreeMemory((BYTE *) pvHeap + cbMapSize);
}
switch (dwErr) {
case ERROR_DISK_FULL:
OutOfDiskSpace();
default:
UnableToExtendMap();
} // end switch
}
}
void *
Malloc(
size_t cb
)
/*++
Routine Description:
Allocates memory from the incremental heap.
Arguments:
cb - count of bytes requested
Return Value:
Pointer to allocated memory.
--*/
{
assert(cb);
if (fCtrlCSignal) {
BadExitCleanup();
}
// non-ilink request
if (!fINCR) {
return(PvAlloc(cb));
}
// DWORD align
cb = (cb + 3) & ~3;
// Grow ILK map as needed
if (cb > cFree) {
GrowILKMap(cb);
}
assert(cb <= cFree);
#if DBG && (_MSC_VER >= 1000)
{
void *ReturnAddress = (void *) _ReturnAddress();
DBEXEC(DB_MEMMGRLOG,
dbprintf("%8lx %8x %2u\n", ReturnAddress, pvCur, cb));
}
#endif // DBG
// update state
pvCur = (BYTE *) pvCur + cb;
cFree -= cb;
return((BYTE *) pvCur - cb);
}
void *
Calloc(
size_t num,
size_t size
)
/*++
Routine Description:
Allocates memory from the incremental heap.
Arguments:
num - count of items
size - size of each item
Return Value:
Pointer to allocated memory.
--*/
{
PVOID pv;
DWORD cb = num*size;
if (!fINCR) {
return(PvAllocZ(cb));
}
assert(cb);
pv = Malloc(cb);
assert(pv);
// zero out everything
memset(pv, 0, cb);
#if DBG && (_MSC_VER >= 1000)
{
void *ReturnAddress = (void *) _ReturnAddress();
DBEXEC(DB_MEMMGRLOG,
dbprintf("%8lx %8x %2u\n", ReturnAddress, pv, cb));
}
#endif // DBG
return(pv);
}
char *
Strdup(
const char *sz
)
/*++
Routine Description:
Allocates memory from the incremental heap.
Arguments:
str - pointer to string to dup
Return Value:
Pointer to allocated memory.
--*/
{
char *szNew;
if (!fINCR) {
return(SzDup(sz));
}
szNew = (char *) Malloc(strlen(sz)+1);
assert(szNew);
strcpy(szNew, sz);
return(szNew);
}
void
Free (
IN PVOID pv,
IN DWORD cb
)
/*++
Routine Description:
Frees a block of memory on heap. MUST BE AT THE END OF
THE HEAP.
Arguments:
pv - pointer to block to be free'd.
cb - size of block
Return Value:
None.
--*/
{
assert(pv);
assert(cb);
assert(pvHeap);
// make sure block is at the end
assert(((DWORD)pv+cb) == (DWORD)pvCur);
// move file pointer back
FileSeek(FileIncrDbHandle, (DWORD)pv-(DWORD) pvHeap, SEEK_SET);
// free space by resetting free pointer and free size
pvCur = (BYTE *) pvCur - cb;
cFree += cb;
}
void FreePv(void *pv)
{
free(pv);
}
void *PvAlloc(size_t cb)
{
void *pv = malloc(cb);
if (pv == NULL) {
OutOfMemory();
}
return(pv);
}
void *PvAllocZ(size_t cb)
{
void *pv = calloc(1, cb);
if (pv == NULL) {
OutOfMemory();
}
return(pv);
}
void *PvRealloc(void *pv, size_t cb)
{
void *pvNew = realloc(pv, cb);
if (pvNew == NULL) {
OutOfMemory();
}
return(pvNew);
}
char *SzDup(const char *sz)
{
char *szNew = _strdup(sz);
if (szNew == NULL) {
OutOfMemory();
}
return(szNew);
}