Files
mars-flaim/xflaim/src/flalloc.cpp
dsandersoremutah c55dab446f Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-01-27 21:06:39 +00:00

1799 lines
41 KiB
C++

//------------------------------------------------------------------------------
// Desc: This file contains the f_alloc, f_calloc, f_realloc, f_recalloc,
// and f_free routines.
//
// Tabs: 3
//
// Copyright (c) 1991, 1993, 1995-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: flalloc.cpp 3112 2006-01-19 13:12:40 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "flaimsys.h"
#ifdef FLM_WIN
// This pragma is needed because FLAIM may be built with a
// packing other than 8-bytes for Windows (such as 1-byte packing).
// Code in FLAIM that uses windows structures and system calls
// MUST use 8-byte packing (the packing used by the O/S).
// See Microsoft technical article Q117388.
#pragma pack( push, enter_windows, 8)
#include <imagehlp.h>
#pragma pack( pop, enter_windows)
#endif
#ifdef FLM_UNIX
#ifdef HAVE_DLADDR
#include <dlfcn.h>
#endif
#endif
#if defined( FLM_UNIX) || defined( FLM_NLM) || defined( FLM_WIN)
#define PTR_IN_MBLK(p,bp,offs) (((FLMBYTE *)(p) > (FLMBYTE *)(bp)) && \
((FLMBYTE *)(p) <= (FLMBYTE *)(bp) + (offs)))
#else
#error Platform not supported
#endif
#ifdef USE_ALT_MEM_MANAGER
// If USE_ALT_MEM_MANAGER is defined, memory allocations will be based on
// a user-supplied module that implements f_alt_malloc, f_alt_free, and
// f_alt_realloc.
// Prototypes
extern "C"
{
void * f_alt_malloc( unsigned size);
void f_alt_free( void * memblock);
void * f_alt_realloc( void * memblock, unsigned size);
}
#endif
#define MEM_PTR_INIT_ARRAY_SIZE 512
#define MEM_MAX_STACK_WALK_DEPTH 32
// If stack tracking is on, leak checking also
// needs to be on.
#ifndef FLM_DEBUG
#ifdef DEBUG_SIM_OUT_OF_MEM
#undef DEBUG_SIM_OUT_OF_MEM
#endif
#endif
#ifdef FLM_DEBUG
// Platform specific stuff needed for tracking leaks
#ifdef FLM_NLM
extern "C"
{
void GetClosestSymbol(
BYTE * szBuffer,
LONG udAddress);
}
#endif
// Local function prototypes
FSTATIC FLMBOOL initMemTracking(
void);
FSTATIC void saveMemTrackingInfo(
F_MEM_HDR * pHdr);
FSTATIC void updateMemTrackingInfo(
F_MEM_HDR * pHdr);
FSTATIC void freeMemTrackingInfo(
FLMBOOL bMutexAlreadyLocked,
FLMUINT uiId,
FLMUINT * puiStack);
#ifdef DEBUG_SIM_OUT_OF_MEM
//one of every OUT_OF_MEM_FREQUENCY calls will fail
#define OUT_OF_MEM_FREQUENCY 40000
//OUT_OF_MEM_SEQUENCE_LENGTH calls in a row will fail
#define OUT_OF_MEM_SEQUENCE_LENGTH 10
FLMBOOL SimulateOutOfMemory()
{
if (
//is the flag turned on
(gv_XFlmSysData.uiOutOfMemSimEnabledFlag ==
(FLMUINT)OUT_OF_MEM_SIM_ENABLED_FLAG) &&
//continuing a sequence of failures
((gv_XFlmSysData.uiSimOutOfMemFailSequence > 0) ||
//failing randomly for the first time, and starting a new sequence
(f_randomChoice( &gv_XFlmSysData.memSimRandomGen, 0, OUT_OF_MEM_FREQUENCY) == 0)
))
{
gv_XFlmSysData.uiSimOutOfMemFailTotal++;
gv_XFlmSysData.uiSimOutOfMemFailSequence++;
//if reached the end of failure sequence, reset back to 0 so the
//sequence will cease
if ( gv_XFlmSysData.uiSimOutOfMemFailSequence >= OUT_OF_MEM_SEQUENCE_LENGTH)
{
gv_XFlmSysData.uiSimOutOfMemFailSequence = 0;
}
return TRUE;
}
else
{
return FALSE;
}
}
#endif //#ifdef DEBUG_SIM_OUT_OF_MEM
#if defined( FLM_NLM)
/************************************************************************
Desc: Returns the current value of EBP--the value of the caller's stack
frame pointer.
*************************************************************************/
void * memGetEBP(void);
#ifdef FLM_MWERKS_NLM
void * memGetEBP(void)
{
__asm
{
mov eax,[ebp]
}
}
#else
#pragma aux memGetEBP = "mov eax,ebp";
#endif
/************************************************************************
Desc: Returns the value at SS:[POS+OFFSET].
*************************************************************************/
void * memValueAtStackOffset(void *pos, int offset);
#ifdef FLM_MWERKS_NLM
void *memValueAtStackOffset(void *, int)
{
__asm
{
mov eax,[ebp+0x8]
mov ebx,[ebp+0xC]
mov eax,ss:[eax+ebx]
}
}
#else
#pragma aux memValueAtStackOffset = "mov eax,ss:[eax+ebx]" parm [eax] [ebx];
#endif
/************************************************************************
Desc:
*************************************************************************/
FLMUINT * memWalkStack()
{
FLMUINT uiLoop;
FLMUINT uiRtnAddr;
FLMUINT uiEbp = (FLMUINT) memGetEBP();
FLMUINT uiAddresses [MEM_MAX_STACK_WALK_DEPTH + 1];
FLMUINT * puiAddresses;
uiEbp = (FLMUINT) memValueAtStackOffset( (void *)uiEbp, 0); // skip addrs we already know
uiRtnAddr = (FLMUINT) memValueAtStackOffset( (void *)uiEbp, 4); // Caller's return addr
for (uiLoop = 0; uiLoop < MEM_MAX_STACK_WALK_DEPTH; uiLoop++)
{
FLMUINT uiOldEbp;
uiAddresses [uiLoop] = uiRtnAddr;
if (!uiEbp)
{
break;
}
uiOldEbp = uiEbp;
uiEbp = (FLMUINT) memValueAtStackOffset( (void *)uiEbp, 0); // Caller's frame ptr
if (!uiEbp || uiEbp <= uiOldEbp || uiEbp > uiOldEbp + 5000)
{
break;
}
uiRtnAddr = (FLMUINT) memValueAtStackOffset( (void *) uiEbp, 4); // Caller's return addr
}
uiAddresses [uiLoop] = 0;
if ((puiAddresses = (FLMUINT *)os_malloc(
sizeof( FLMUINT) * (uiLoop+1))) != NULL)
{
f_memcpy( puiAddresses, &uiAddresses [0], sizeof( FLMUINT) * (uiLoop + 1));
}
return( puiAddresses);
}
#elif defined( FLM_WIN)
/********************************************************************
Desc: Walk the call stack.
*********************************************************************/
FLMUINT * memWalkStack()
{
STACKFRAME64 stackFrame;
CONTEXT context;
DWORD machineType;
FLMUINT uiLoop;
FLMUINT uiAddresses [MEM_MAX_STACK_WALK_DEPTH + 1];
FLMUINT * puiAddresses;
HANDLE hThread;
HANDLE hProcess;
FLMUINT uiAddrCount;
f_memset( &stackFrame, 0, sizeof( stackFrame));
f_memset( &context, 0, sizeof( context));
#ifdef FLM_64BIT
machineType = IMAGE_FILE_MACHINE_IA64;
#else
machineType = IMAGE_FILE_MACHINE_I386;
#endif
// While you can continue walking the stack...
unsigned vEBP, vEIP;
__asm mov vEBP, ebp
__asm call near nextinstr
nextinstr:
__asm pop vEIP;
context.Ebp = vEBP;
context.Eip = vEIP;
stackFrame.AddrPC.Offset = vEIP;
stackFrame.AddrFrame.Offset = vEBP;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Mode = AddrModeFlat;
// Must lock the mutex because StackWalk is not thread safe.
f_mutexLock( gv_XFlmSysData.hMemTrackingMutex);
hProcess = OpenProcess( PROCESS_VM_READ, FALSE, GetCurrentProcessId());
hThread = OpenThread( THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME,
FALSE, GetCurrentThreadId());
// We have already processed the address inside memWalkStack
uiAddrCount = 1;
uiLoop = 0;
for (;;)
{
if (!StackWalk64( machineType, hProcess, hThread, &stackFrame,
&context, NULL,
SymFunctionTableAccess64, SymGetModuleBase64, NULL))
{
break;
}
// Skip the first two addresses. These represent the following:
// 1) memWalkStack
// 2) saveMemTrackingInfo or updateMemTrackingInfo
// We don't need to see them in the stack trace.
uiAddrCount++;
if (uiAddrCount > 2)
{
uiAddresses [uiLoop] = (FLMUINT)stackFrame.AddrReturn.Offset;
uiLoop++;
if (uiLoop == MEM_MAX_STACK_WALK_DEPTH)
{
break;
}
}
}
f_mutexUnlock( gv_XFlmSysData.hMemTrackingMutex);
uiAddresses [uiLoop] = 0;
if ((puiAddresses = (FLMUINT *)os_malloc(
sizeof( FLMUINT) * (uiLoop+1))) != NULL)
{
f_memcpy( puiAddresses, &uiAddresses [0], sizeof( FLMUINT) * (uiLoop + 1));
}
return( puiAddresses);
}
#else
FLMUINT * memWalkStack()
{
return( NULL);
}
#endif
/********************************************************************
Desc: Initialize memory tracking
*********************************************************************/
FSTATIC FLMBOOL initMemTracking( void)
{
RCODE rc;
F_MUTEX memMutex;
if (!gv_XFlmSysData.bMemTrackingInitialized && !gv_XFlmSysData.uiInitThreadId)
{
gv_XFlmSysData.uiInitThreadId = f_threadId();
rc = f_mutexCreate( &memMutex);
f_sleep( 50);
// Only set to initialized if we were the last thread
// to set gv_XFlmSysData.uiInitThreadId
if (f_threadId() == gv_XFlmSysData.uiInitThreadId)
{
if (RC_OK( rc))
{
gv_XFlmSysData.hMemTrackingMutex = memMutex;
}
else
{
gv_XFlmSysData.hMemTrackingMutex = F_MUTEX_NULL;
}
#ifdef FLM_WIN
SymSetOptions( SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
gv_XFlmSysData.hMemProcess = GetCurrentProcess();
SymInitialize( gv_XFlmSysData.hMemProcess, NULL, TRUE);
#endif
gv_XFlmSysData.bMemTrackingInitialized = TRUE;
}
else
{
if (RC_OK( rc))
{
f_mutexDestroy( &memMutex);
}
}
}
// Go into a loop until we see initialized flag set to TRUE
// Could be another thread that is doing it.
while (!gv_XFlmSysData.bMemTrackingInitialized)
{
f_sleep( 10);
}
return( (gv_XFlmSysData.hMemTrackingMutex != F_MUTEX_NULL) ? TRUE : FALSE);
}
/********************************************************************
Desc: Save memory tracking information - called on alloc or realloc.
*********************************************************************/
FSTATIC void saveMemTrackingInfo(
F_MEM_HDR * pHdr)
{
FLMUINT uiNewCnt;
FLMUINT uiId;
void ** pNew;
if (gv_XFlmSysData.bTrackLeaks && initMemTracking())
{
f_mutexLock( gv_XFlmSysData.hMemTrackingMutex);
// See if there is enough room in the array
if (gv_XFlmSysData.uiMemNumPtrs == gv_XFlmSysData.uiMemTrackingPtrArraySize)
{
// If array is not initialized, use initial count. Otherwise
// double the size.
uiNewCnt = (FLMUINT)((!gv_XFlmSysData.uiMemTrackingPtrArraySize)
? MEM_PTR_INIT_ARRAY_SIZE
: gv_XFlmSysData.uiMemTrackingPtrArraySize * 2);
if ((pNew = (void **)os_malloc( sizeof( void *) * uiNewCnt)) != NULL)
{
// Copy the pointers from the old array, if any,
// into the newly allocated array.
if (gv_XFlmSysData.uiMemTrackingPtrArraySize)
{
f_memcpy( pNew, gv_XFlmSysData.ppvMemTrackingPtrs,
sizeof( void *) * gv_XFlmSysData.uiMemTrackingPtrArraySize);
os_free( gv_XFlmSysData.ppvMemTrackingPtrs);
gv_XFlmSysData.ppvMemTrackingPtrs = NULL;
}
f_memset( &pNew [gv_XFlmSysData.uiMemTrackingPtrArraySize], 0,
sizeof( void *) * (uiNewCnt - gv_XFlmSysData.uiMemTrackingPtrArraySize));
gv_XFlmSysData.ppvMemTrackingPtrs = pNew;
gv_XFlmSysData.uiMemTrackingPtrArraySize = uiNewCnt;
}
}
// If we are still full, we were not able to reallocate memory, so we
// do nothing.
if (gv_XFlmSysData.uiMemNumPtrs == gv_XFlmSysData.uiMemTrackingPtrArraySize)
{
pHdr->uiAllocationId = 0;
}
else
{
// Find an empty slot - there has to be one!
uiId = gv_XFlmSysData.uiMemNextPtrSlotToUse;
while (gv_XFlmSysData.ppvMemTrackingPtrs [uiId])
{
if (++uiId == gv_XFlmSysData.uiMemTrackingPtrArraySize)
{
uiId = 0;
}
}
// Allocation ID in the header is offset by one to avoid
// using a value of zero.
pHdr->uiAllocationId = uiId + 1;
gv_XFlmSysData.ppvMemTrackingPtrs [uiId] = pHdr;
gv_XFlmSysData.uiMemNumPtrs++;
if ((gv_XFlmSysData.uiMemNextPtrSlotToUse = uiId + 1) ==
gv_XFlmSysData.uiMemTrackingPtrArraySize)
{
gv_XFlmSysData.uiMemNextPtrSlotToUse = 0;
}
}
pHdr->uiAllocCnt = ++gv_XFlmSysData.uiAllocCnt;
f_mutexUnlock( gv_XFlmSysData.hMemTrackingMutex);
}
else
{
pHdr->uiAllocationId = 0;
pHdr->uiAllocCnt = 0;
}
// Follow the stack.
if (gv_XFlmSysData.bTrackLeaks && gv_XFlmSysData.bStackWalk)
{
pHdr->puiStack = memWalkStack();
}
else
{
pHdr->puiStack = NULL;
}
}
/********************************************************************
Desc: Update memory tracking information - called after realloc
*********************************************************************/
FSTATIC void updateMemTrackingInfo(
F_MEM_HDR * pHdr)
{
if (pHdr->puiStack)
{
os_free( pHdr->puiStack);
pHdr->puiStack = NULL;
}
if (gv_XFlmSysData.bTrackLeaks && gv_XFlmSysData.bStackWalk)
{
pHdr->puiStack = memWalkStack();
}
}
/********************************************************************
Desc: Free memory tracking information - called on free.
*********************************************************************/
FSTATIC void freeMemTrackingInfo(
FLMBOOL bMutexAlreadyLocked,
FLMUINT uiId,
FLMUINT * puiStack
)
{
if (uiId)
{
// NOTE: If uiId is non-zero, it means we had to have
// successfully initialized, so we are guaranteed to
// have a mutex.
if ( !bMutexAlreadyLocked)
{
f_mutexLock( gv_XFlmSysData.hMemTrackingMutex);
}
// Allocation ID in the header is offset by one so that it
// is never zero - a value of zero means that the allocation
// does not have a slot for tracking it in the array.
gv_XFlmSysData.ppvMemTrackingPtrs [uiId - 1] = NULL;
flmAssert( gv_XFlmSysData.uiMemNumPtrs);
gv_XFlmSysData.uiMemNumPtrs--;
if ( !bMutexAlreadyLocked)
{
f_mutexUnlock( gv_XFlmSysData.hMemTrackingMutex);
}
}
// Free the stack information, if any.
if (puiStack)
{
os_free( puiStack);
}
}
/********************************************************************
Desc: Log memory leaks.
*********************************************************************/
void logMemLeak(
F_MEM_HDR * pHdr)
{
char szTmpBuffer [1024];
FLMUINT uiMsgBufSize;
char * pszMessageBuffer;
char * pszTmp;
IF_FileHdl * pFileHdl = NULL;
F_FileSystem fileSys;
FLMBOOL bClearFileSys = FALSE;
FLMBOOL bSaveTrackLeaks = gv_XFlmSysData.bTrackLeaks;
gv_XFlmSysData.bTrackLeaks = FALSE;
// Need a big buffer to show an entire stack.
uiMsgBufSize = 20480;
if ((pszMessageBuffer = (char *)os_malloc( uiMsgBufSize)) == NULL)
{
pszMessageBuffer = &szTmpBuffer [0];
uiMsgBufSize = sizeof( szTmpBuffer);
}
pszTmp = pszMessageBuffer;
if( !gv_pFileSystem)
{
gv_pFileSystem = &fileSys;
bClearFileSys = TRUE;
}
// Format message to be logged.
f_strcpy( pszTmp, "Abort=Debug, Retry=Continue, Ignore=Don't Show\r\n");
while (*pszTmp)
{
pszTmp++;
}
#if defined( FLM_WIN) && defined( FLM_64BIT)
f_sprintf( pszTmp, "Unfreed Pointer: 0x%016I64x\r\n", (FLMUINT)(&pHdr [1]));
#else
f_sprintf( pszTmp, "Unfreed Pointer: 0x%08x\r\n",
(unsigned)((FLMUINT)(&pHdr [1])));
#endif
while (*pszTmp)
{
pszTmp++;
}
if (pHdr->pszFileName)
{
f_sprintf( pszTmp, "Source: %s, Line#: %u\r\n", pHdr->pszFileName,
(unsigned)pHdr->iLineNumber);
while (*pszTmp)
{
pszTmp++;
}
}
if (pHdr->uiAllocCnt)
{
f_sprintf( pszTmp, "Malloc #: %u\r\n", (unsigned)pHdr->uiAllocCnt);
while (*pszTmp)
{
pszTmp++;
}
}
f_sprintf( (char *)pszTmp, "Size: %u bytes\r\n", (unsigned)pHdr->uiDataSize);
while (*pszTmp)
{
pszTmp++;
}
if (pHdr->puiStack)
{
FLMUINT * puiStack = pHdr->puiStack;
FLMUINT uiLen = pszTmp - pszMessageBuffer;
char szFuncName [200];
char * pszFuncName;
#ifdef FLM_WIN
IMAGEHLP_SYMBOL * pImgHlpSymbol;
pImgHlpSymbol = (IMAGEHLP_SYMBOL *)os_malloc(
sizeof( IMAGEHLP_SYMBOL) + 100);
#endif
while (*puiStack)
{
szFuncName [0] = 0;
#ifdef FLM_WIN
if (pImgHlpSymbol)
{
#ifdef FLM_64BIT
DWORD64 udDisplacement;
#else
DWORD udDisplacement;
#endif
pImgHlpSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
pImgHlpSymbol->Address = *puiStack;
pImgHlpSymbol->MaxNameLength = 100;
if (SymGetSymFromAddr( gv_XFlmSysData.hMemProcess, *puiStack,
&udDisplacement, pImgHlpSymbol))
{
f_sprintf( szFuncName, "\t%s + %X\r\n",
(char *)(&pImgHlpSymbol->Name [0]),
udDisplacement);
}
}
#elif defined( FLM_NLM)
{
szFuncName [0] = '\t';
GetClosestSymbol( (BYTE *)(&szFuncName[1]), (LONG)(*puiStack));
}
#else
#ifdef HAVE_DLADDR
{
Dl_info dlip;
if (dladdr( (void *)(*puiStack), &dlip) != 0 && dlip.dli_sname)
{
const char * pszFileName;
if (dlip.dli_saddr != (void *)(*puiStack))
{
pszFileName = strrchr(dlip.dli_fname, '/');
if (!pszFileName)
{
pszFileName = dlip.dli_fname;
}
else
{
pszFileName++; // skip over slash
}
f_sprintf( szFuncName, "\t0x%08x (%s)\r\n",
(unsigned)(*puiStack), pszFileName);
}
else
{
f_sprintf( szFuncName, "\t%s\r\n", dlip.dli_sname);
}
}
}
#endif
#endif
// If szFuncName [0] is zero, we didn't find a name, so we
// just output the address in HEX.
if (!szFuncName [0])
{
f_sprintf( szFuncName, "\t0x%08X\r\n", (unsigned)*puiStack );
}
// Output whatever portion of the name will fit into the
// message buffer.
pszFuncName = &szFuncName [0];
while (*pszFuncName && uiLen < uiMsgBufSize - 1)
{
*pszTmp++ = *pszFuncName++;
uiLen++;
}
// Process next address in the stack.
puiStack++;
}
*pszTmp = 0;
#ifdef FLM_WIN
if (pImgHlpSymbol)
{
os_free( pImgHlpSymbol);
}
#endif
}
#ifdef FLM_WIN
FLMINT iRet;
iRet = MessageBox( NULL, (LPCTSTR)pszMessageBuffer, "WIN32 Memory Testing",
MB_ABORTRETRYIGNORE | MB_ICONINFORMATION | MB_TASKMODAL
| MB_SETFOREGROUND | MB_DEFBUTTON2);
if (iRet == IDIGNORE)
{
gv_XFlmSysData.bLogLeaks = TRUE;
}
else if (iRet == IDABORT)
{
flmAssert( 0);
}
#else
gv_XFlmSysData.bLogLeaks = TRUE;
#endif
if (gv_XFlmSysData.bLogLeaks)
{
F_FileSystem FileSystem;
RCODE rc;
FLMUINT uiDummy;
#ifdef FLM_NLM
const char * pszErrPath = "sys:\\memtest.ert";
#else
const char * pszErrPath = "memtest.ert";
#endif
if (RC_BAD( rc = FileSystem.Open( pszErrPath, XFLM_IO_RDWR | XFLM_IO_SH_DENYNONE,
&pFileHdl)))
{
if (rc == NE_XFLM_IO_PATH_NOT_FOUND)
{
rc = FileSystem.Create( pszErrPath, XFLM_IO_RDWR | XFLM_IO_SH_DENYNONE,
&pFileHdl);
}
}
else
{
// Position to append to file.
rc = pFileHdl->Seek( 0, XFLM_IO_SEEK_END, NULL);
}
// If we successfully opened the file, write to it.
if (RC_OK( rc))
{
if (RC_OK( pFileHdl->Write( XFLM_IO_CURRENT_POS,
(FLMUINT)(pszTmp - pszMessageBuffer),
pszMessageBuffer, &uiDummy)))
{
(void)pFileHdl->Flush();
}
pFileHdl->Close();
}
}
//Exit:
if (pFileHdl)
{
pFileHdl->Release();
}
if( bClearFileSys)
{
gv_pFileSystem = NULL;
}
if (pszMessageBuffer != &szTmpBuffer [0])
{
os_free( pszMessageBuffer);
}
gv_XFlmSysData.bTrackLeaks = bSaveTrackLeaks;
}
#endif
/********************************************************************
Desc: Initialize memory - if not already done.
*********************************************************************/
void f_memoryInit( void)
{
#ifdef FLM_DEBUG
(void)initMemTracking();
#endif
}
/********************************************************************
Desc: Clean up memory and check for unfreed memory.
*********************************************************************/
void f_memoryCleanup( void)
{
#ifdef FLM_DEBUG
if (initMemTracking())
{
FLMUINT uiId;
F_MEM_HDR * pHdr;
f_mutexLock( gv_XFlmSysData.hMemTrackingMutex);
for (uiId = 0; uiId < gv_XFlmSysData.uiMemTrackingPtrArraySize; uiId++)
{
if ((pHdr = (F_MEM_HDR *)gv_XFlmSysData.ppvMemTrackingPtrs [uiId]) != NULL)
{
logMemLeak( pHdr);
freeMemTrackingInfo( TRUE, uiId + 1, pHdr->puiStack);
}
}
// Free the memory pointer array.
os_free( gv_XFlmSysData.ppvMemTrackingPtrs);
gv_XFlmSysData.ppvMemTrackingPtrs = NULL;
gv_XFlmSysData.uiMemTrackingPtrArraySize = 0;
gv_XFlmSysData.uiMemNumPtrs = 0;
f_mutexUnlock( gv_XFlmSysData.hMemTrackingMutex);
// Free up the mutex.
f_mutexDestroy( &gv_XFlmSysData.hMemTrackingMutex);
// Reset to unitialized state.
gv_XFlmSysData.uiInitThreadId = 0;
gv_XFlmSysData.hMemTrackingMutex = F_MUTEX_NULL;
gv_XFlmSysData.bMemTrackingInitialized = FALSE;
#ifdef FLM_WIN
SymCleanup( gv_XFlmSysData.hMemProcess);
#endif
}
#endif
}
/********************************************************************
Desc: Allocate Memory.
*********************************************************************/
#ifdef FLM_DEBUG
RCODE f_allocImp(
FLMUINT uiSize,
void ** ppvPtr,
FLMBOOL bAllocFromNewOp,
const char * pszFileName,
FLMINT iLineNumber
)
#else
RCODE f_allocImp(
FLMUINT uiSize,
void ** ppvPtr
)
#endif
{
RCODE rc = NE_XFLM_OK;
F_MEM_HDR * pHdr;
#ifdef DEBUG_SIM_OUT_OF_MEM
if ( SimulateOutOfMemory())
{
*ppvPtr = NULL;
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
#endif
if ((pHdr = (F_MEM_HDR *)os_malloc( uiSize +
sizeof( F_MEM_HDR) +
F_PICKET_FENCE_SIZE)) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
pHdr->uiDataSize = uiSize;
*ppvPtr = (void *)(&pHdr [1]);
#ifdef FLM_DEBUG
pHdr->bAllocFromNewOp = bAllocFromNewOp;
pHdr->iLineNumber = iLineNumber;
pHdr->pszFileName = pszFileName;
saveMemTrackingInfo( pHdr);
#if F_PICKET_FENCE_SIZE
f_memcpy( ((FLMBYTE *)(*ppvPtr)) + uiSize,
F_PICKET_FENCE, F_PICKET_FENCE_SIZE);
#endif
#endif
Exit:
return( rc);
}
/********************************************************************
Desc: Allocate and initialize memory.
*********************************************************************/
#ifdef FLM_DEBUG
RCODE f_callocImp(
FLMUINT uiSize,
void ** ppvPtr,
const char * pszFileName,
FLMINT iLineNumber
)
#else
RCODE f_callocImp(
FLMUINT uiSize,
void ** ppvPtr
)
#endif
{
RCODE rc = NE_XFLM_OK;
F_MEM_HDR * pHdr;
#ifdef DEBUG_SIM_OUT_OF_MEM
if ( SimulateOutOfMemory())
{
*ppvPtr = NULL;
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
#endif
if ((pHdr = (F_MEM_HDR *)os_malloc( uiSize +
sizeof( F_MEM_HDR) +
F_PICKET_FENCE_SIZE)) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
pHdr->uiDataSize = uiSize;
*ppvPtr = (void *)(&pHdr [1]);
f_memset( *ppvPtr, 0, uiSize);
#ifdef FLM_DEBUG
pHdr->bAllocFromNewOp = FALSE;
pHdr->iLineNumber = iLineNumber;
pHdr->pszFileName = pszFileName;
saveMemTrackingInfo( pHdr);
#if F_PICKET_FENCE_SIZE
f_memcpy( ((FLMBYTE *)(*ppvPtr)) + uiSize,
F_PICKET_FENCE, F_PICKET_FENCE_SIZE);
#endif
#endif
Exit:
return( rc);
}
/********************************************************************
Desc: Reallocate memory.
*********************************************************************/
#ifdef FLM_DEBUG
RCODE f_reallocImp(
FLMUINT uiSize,
void ** ppvPtr,
const char * pszFileName,
FLMINT iLineNumber
)
#else
RCODE f_reallocImp(
FLMUINT uiSize,
void ** ppvPtr
)
#endif
{
RCODE rc = NE_XFLM_OK;
F_MEM_HDR * pNewHdr;
#ifdef FLM_DEBUG
F_MEM_HDR * pOldHdr;
FLMUINT uiOldAllocationId;
FLMUINT * puiOldStack;
#endif
#ifdef DEBUG_SIM_OUT_OF_MEM
if ( SimulateOutOfMemory())
{
*ppvPtr = NULL;
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
#endif
if (!(*ppvPtr))
{
#ifdef FLM_DEBUG
rc = f_allocImp( uiSize, ppvPtr, FALSE, pszFileName, iLineNumber);
#else
rc = f_allocImp( uiSize, ppvPtr);
#endif
goto Exit;
}
#ifdef FLM_DEBUG
pOldHdr = (F_MEM_HDR *)F_GET_ALLOC_PTR( *ppvPtr);
#if F_PICKET_FENCE_SIZE
// Verify the old picket fence
if (f_memcmp( ((FLMBYTE *)(*ppvPtr)) + pOldHdr->uiDataSize,
F_PICKET_FENCE, F_PICKET_FENCE_SIZE) != 0)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_MEM);
goto Exit;
}
#endif
// Cannot realloc memory that was allocated via a new operator
if (pOldHdr->bAllocFromNewOp)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_MEM);
goto Exit;
}
uiOldAllocationId = pOldHdr->uiAllocationId;
puiOldStack = pOldHdr->puiStack;
#endif
if ((pNewHdr = (F_MEM_HDR *)os_realloc( F_GET_ALLOC_PTR( *ppvPtr),
uiSize + sizeof( F_MEM_HDR) +
F_PICKET_FENCE_SIZE)) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
pNewHdr->uiDataSize = uiSize;
*ppvPtr = (void *)(&pNewHdr [1]);
#ifdef FLM_DEBUG
pNewHdr->bAllocFromNewOp = FALSE;
pNewHdr->iLineNumber = iLineNumber;
pNewHdr->pszFileName = pszFileName;
if (pNewHdr != pOldHdr)
{
freeMemTrackingInfo( FALSE, uiOldAllocationId, puiOldStack);
saveMemTrackingInfo( pNewHdr);
}
else
{
updateMemTrackingInfo( pNewHdr);
}
#if F_PICKET_FENCE_SIZE
f_memcpy( ((FLMBYTE *)(*ppvPtr)) + uiSize,
F_PICKET_FENCE, F_PICKET_FENCE_SIZE);
#endif
#endif
Exit:
return( rc);
}
/********************************************************************
Desc: Reallocate memory, and initialize the new part.
*********************************************************************/
#ifdef FLM_DEBUG
RCODE f_recallocImp(
FLMUINT uiSize,
void ** ppvPtr,
const char * pszFileName,
FLMINT iLineNumber
)
#else
RCODE f_recallocImp(
FLMUINT uiSize,
void ** ppvPtr
)
#endif
{
RCODE rc = NE_XFLM_OK;
F_MEM_HDR * pNewHdr;
FLMUINT uiOldSize;
#ifdef FLM_DEBUG
F_MEM_HDR * pOldHdr;
FLMUINT uiOldAllocationId;
FLMUINT * puiOldStack;
#endif
#ifdef DEBUG_SIM_OUT_OF_MEM
if ( SimulateOutOfMemory())
{
*ppvPtr = NULL;
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
#endif
if (!(*ppvPtr))
{
#ifdef FLM_DEBUG
rc = f_callocImp( uiSize, ppvPtr, pszFileName, iLineNumber);
#else
rc = f_callocImp( uiSize, ppvPtr);
#endif
goto Exit;
}
#ifdef FLM_DEBUG
pOldHdr = (F_MEM_HDR *)F_GET_ALLOC_PTR( *ppvPtr);
#if F_PICKET_FENCE_SIZE
// Verify the old picket fence
if (f_memcmp( ((FLMBYTE *)(*ppvPtr)) + pOldHdr->uiDataSize,
F_PICKET_FENCE, F_PICKET_FENCE_SIZE) != 0)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_MEM);
goto Exit;
}
#endif
// Cannot realloc memory that was allocated via a new operator
if (pOldHdr->bAllocFromNewOp)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_MEM);
goto Exit;
}
uiOldAllocationId = pOldHdr->uiAllocationId;
puiOldStack = pOldHdr->puiStack;
#endif
uiOldSize = F_GET_MEM_DATA_SIZE( *ppvPtr);
if ((pNewHdr = (F_MEM_HDR *)os_realloc( F_GET_ALLOC_PTR( *ppvPtr),
uiSize + sizeof( F_MEM_HDR) +
F_PICKET_FENCE_SIZE)) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
pNewHdr->uiDataSize = uiSize;
*ppvPtr = (void *)(&pNewHdr [1]);
if (uiOldSize < uiSize)
{
f_memset( ((FLMBYTE *)(*ppvPtr)) + uiOldSize, 0,
uiSize - uiOldSize);
}
#ifdef FLM_DEBUG
pNewHdr->bAllocFromNewOp = FALSE;
pNewHdr->iLineNumber = iLineNumber;
pNewHdr->pszFileName = pszFileName;
if (pNewHdr != pOldHdr)
{
freeMemTrackingInfo( FALSE, uiOldAllocationId, puiOldStack);
saveMemTrackingInfo( pNewHdr);
}
else
{
updateMemTrackingInfo( pNewHdr);
}
#if F_PICKET_FENCE_SIZE
f_memcpy( ((FLMBYTE *)(*ppvPtr)) + uiSize,
F_PICKET_FENCE, F_PICKET_FENCE_SIZE);
#endif
#endif
Exit:
return( rc);
}
/********************************************************************
Desc: Free previously allocated memory.
*********************************************************************/
void f_freeImp(
void ** ppvPtr,
FLMBOOL bFreeFromDeleteOp)
{
#ifndef FLM_DEBUG
F_UNREFERENCED_PARM( bFreeFromDeleteOp);
#endif
if (*ppvPtr)
{
#ifdef FLM_DEBUG
F_MEM_HDR * pHdr = (F_MEM_HDR *)F_GET_ALLOC_PTR( *ppvPtr);
if (pHdr->bAllocFromNewOp && !bFreeFromDeleteOp ||
!pHdr->bAllocFromNewOp && bFreeFromDeleteOp)
{
// Either trying to free memory using f_free when
// allocated from new, or trying to free memory
// using delete when allocated from f_alloc,
// f_calloc, f_realloc, or f_recalloc.
RC_UNEXPECTED_ASSERT( NE_XFLM_MEM);
return;
}
#if F_PICKET_FENCE_SIZE
// Check the picket fence
if (f_memcmp( ((FLMBYTE *)(*ppvPtr)) + pHdr->uiDataSize,
F_PICKET_FENCE, F_PICKET_FENCE_SIZE) != 0)
{
RC_UNEXPECTED_ASSERT( NE_XFLM_MEM);
}
#endif
freeMemTrackingInfo( FALSE, pHdr->uiAllocationId, pHdr->puiStack);
#endif
os_free( F_GET_ALLOC_PTR( *ppvPtr));
*ppvPtr = NULL;
}
}
#ifdef FLM_DEBUG
/********************************************************************
Desc: Reset the stack information for an allocation.
*********************************************************************/
void f_resetStackInfoImp(
void * pvPtr,
const char * pszFileName,
FLMINT iLineNumber
)
{
if (pvPtr)
{
F_MEM_HDR * pHdr = (F_MEM_HDR *)F_GET_ALLOC_PTR( pvPtr);
pHdr->iLineNumber = iLineNumber;
pHdr->pszFileName = pszFileName;
f_mutexLock( gv_XFlmSysData.hMemTrackingMutex);
pHdr->uiAllocCnt = ++gv_XFlmSysData.uiAllocCnt;
f_mutexUnlock( gv_XFlmSysData.hMemTrackingMutex);
updateMemTrackingInfo( pHdr);
}
}
#endif
/************************************************************************
Desc: Destructor
*************************************************************************/
F_Pool::~F_Pool()
{
poolFree();
}
/************************************************************************
Desc: Initialize a smart pool memory structure. A smart pool is one that
will adjust it's block allocation size based on statistics it
gathers within the POOL_STATS structure. For each pool that user
wants to use smart memory management a global POOL_STATS structure
should be declared. The POOL_STATS structure is used to track the
total bytes allocated and determine what the correct pool block
size should be.
*************************************************************************/
void F_Pool::smartPoolInit(
POOL_STATS * pPoolStats)
{
m_pPoolStats = pPoolStats;
if (m_pPoolStats && m_pPoolStats->uiCount)
{
setInitialSmartPoolBlkSize();
}
else
{
m_uiBlockSize = 2048;
}
}
/****************************************************************************
Desc: Allocates a block of memory from a memory pool.
Note: If the number of bytes is more than the what is left in the
current block then a new block will be allocated and the lbkl element
of the PMS will be updated.
****************************************************************************/
RCODE F_Pool::poolAlloc(
FLMUINT uiSize,
void ** ppvPtr
)
{
RCODE rc = NE_XFLM_OK;
MBLK * pBlock = m_pLastBlock;
MBLK * pOldLastBlock = pBlock;
FLMBYTE * pucFreePtr;
FLMUINT uiBlockSize;
// Adjust the size to a machine word boundary
// NOTE: ORed and ANDed 0x800.. & 0x7FFF to prevent partial
// stalls on Netware
if (uiSize & (FLM_ALLOC_ALIGN | 0x80000000))
{
uiSize = ((uiSize + FLM_ALLOC_ALIGN) & (~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF));
}
// Check if room in block
if (!pBlock || uiSize > pBlock->uiFreeSize)
{
// Check if previous block has space for allocation
if (pBlock &&
pBlock->pPrevBlock &&
uiSize <= pBlock->pPrevBlock->uiFreeSize)
{
pBlock = pBlock->pPrevBlock;
goto Exit;
}
// Not enough memory in block - allocate new block
// Determine the block size:
// 1) start with max of last block size, initial pool size, or alloc size
// 2) if this is an extra block alloc then increase the size by 1/2
// 3) adjust size to include block header
uiBlockSize = (pBlock) ? pBlock->uiBlockSize : m_uiBlockSize;
uiBlockSize = f_max( uiSize, uiBlockSize);
if (pBlock &&
uiBlockSize == pBlock->uiBlockSize &&
uiBlockSize <= 32769)
{
uiBlockSize += uiBlockSize / 2;
}
// Add in extra bytes for block overhead
uiBlockSize += sizeof( MBLK);
if (RC_BAD( rc = f_alloc( uiBlockSize, &pBlock)))
{
goto Exit;
}
// Initialize the block elements
pBlock->uiBlockSize = uiBlockSize;
pBlock->uiFreeOffset = sizeof( MBLK);
pBlock->uiFreeSize = uiBlockSize - sizeof( MBLK);
// Link in newly allocated block
m_pLastBlock = pBlock;
pBlock->pPrevBlock = pOldLastBlock;
}
Exit:
if (RC_OK( rc))
{
pucFreePtr = (FLMBYTE *)pBlock;
pucFreePtr += pBlock->uiFreeOffset; // Point to free space
pBlock->uiFreeOffset += uiSize; // Modify free offset
pBlock->uiFreeSize -= uiSize; // Modify free size
m_uiBytesAllocated += uiSize;
*ppvPtr = (void *)pucFreePtr;
}
else
{
*ppvPtr = NULL;
}
return( rc);
}
/****************************************************************************
Desc: Allocates a block of memory from a memory pool.
****************************************************************************/
RCODE F_Pool::poolCalloc(
FLMUINT uiSize,
void ** ppvPtr)
{
RCODE rc;
if (RC_OK( rc = poolAlloc( uiSize, ppvPtr)))
{
f_memset( *ppvPtr, 0, uiSize);
}
return( rc);
}
/****************************************************************************
Desc : Releases all memory allocated to a pool.
Note : All memory allocated to the pool is returned to the operating system.
*****************************************************************************/
void F_Pool::poolFree( void)
{
MBLK * pBlock = m_pLastBlock;
MBLK * pPrevBlock;
// Free all blocks in chain
while (pBlock)
{
pPrevBlock = pBlock->pPrevBlock;
f_free( &pBlock);
pBlock = pPrevBlock;
}
m_pLastBlock = NULL;
// For Smart Pools update pool statictics
if (m_pPoolStats)
{
updateSmartPoolStats();
}
}
/****************************************************************************
Desc: Resets memory blocks allocated to a pool.
Note: Will reset the free space in the first memory block, and if
any extra blocks exist they will be freed (destroyed).
*****************************************************************************/
void F_Pool::poolReset(
void * pvMark,
// [IN] If pvMark is NULL, the first pool block is emptied and all
// other blocks in the list are released to the operating system.
// If pvMark is non-NULL, the pool list is searched for the block
// containing pvMark. All pool blocks following pvMark are
// released and the block containing pvMark is is reset to
// the byte referenced by pvMark.
FLMBOOL bReduceFirstBlock
)
{
MBLK * pBlock = m_pLastBlock;
MBLK * pPrevBlock;
if (!pBlock)
{
return;
}
// For Smart Pools update pool statictics
if (m_pPoolStats)
{
updateSmartPoolStats();
}
if (pvMark)
{
freeToMark( pvMark);
return;
}
// Free all blocks except last one in chain -- which is really
// the first block allocated. This will help us keep memory from
// getting fragmented.
while (pBlock->pPrevBlock)
{
pPrevBlock = pBlock->pPrevBlock;
f_free( &pBlock);
pBlock = pPrevBlock;
}
if (pBlock->uiBlockSize - sizeof(MBLK) > m_uiBlockSize && bReduceFirstBlock)
{
// The first block was not the default size, so free it
f_free( &pBlock);
m_pLastBlock = NULL;
}
else
{
// Reset the allocation pointers in the first block
pBlock->uiFreeOffset = sizeof( MBLK);
pBlock->uiFreeSize = pBlock->uiBlockSize - sizeof( MBLK);
m_pLastBlock = pBlock;
#ifdef FLM_MEM_CHK
{
/* memset the reset memory so someone pointing to it will get a error. */
FLMBYTE * pucPtr = (FLMBYTE *) pBlock;
pucPtr += pBlock->uiFreeOffset;
f_memset( pucPtr, 'r', pBlock->uiFreeSize); // Set memory to 'r' for Reset
}
#endif
}
// on smart pools adjust the initial block size on pool resets
if (m_pPoolStats)
{
setInitialSmartPoolBlkSize();
}
}
/****************************************************************************
Desc: Frees memory until the pvMark is found.
****************************************************************************/
void F_Pool::freeToMark(
void * pvMark) // free until pvMark found
{
MBLK * pBlock = m_pLastBlock;
MBLK * pPrevBlock;
// Initialize pool to no blocks
m_pLastBlock = NULL;
while (pBlock)
{
pPrevBlock = pBlock->pPrevBlock;
// Check for mark point
if (PTR_IN_MBLK( pvMark, pBlock, pBlock->uiBlockSize))
{
FLMUINT uiOldFreeOffset = pBlock->uiFreeOffset;
// Reset uiFreeOffset and uiFreeSize variables
pBlock->uiFreeOffset = (FLMUINT)((FLMBYTE *)pvMark -
(FLMBYTE *)pBlock);
pBlock->uiFreeSize = pBlock->uiBlockSize - pBlock->uiFreeOffset;
#if defined( FLM_MEM_CHK) || defined( MEM_TEST)
{
// memset the memory so someone pointing to it will get a error.
FLMBYTE * pucPtr = (FLMBYTE *)pBlock;
pucPtr += pBlock->uiFreeOffset;
f_memset( pucPtr, 'r', pBlock->uiFreeSize); // Set memory to 'r' for Reset
}
#endif
// For Smart Pools deduct the bytes allocated since pool mark
if (m_pPoolStats)
{
flmAssert( uiOldFreeOffset >= pBlock->uiFreeOffset);
m_uiBytesAllocated -= (uiOldFreeOffset - pBlock->uiFreeOffset);
}
break;
}
if (m_pPoolStats)
{
m_uiBytesAllocated -= (pBlock->uiFreeOffset - sizeof( MBLK));
}
f_free( &pBlock);
pBlock = pPrevBlock;
}
if (pBlock)
{
m_pLastBlock = pBlock;
}
}
#undef new
#undef delete
/****************************************************************************
Desc:
****************************************************************************/
void * XF_Base::operator new(
FLMSIZET uiSize)
{
void * pvReturnPtr = NULL;
// NOTICE: You should be using f_new so that we can track memory leaks
RC_UNEXPECTED_ASSERT( NE_XFLM_MEM);
#ifdef FLM_DEBUG
f_allocImp( uiSize, &pvReturnPtr, TRUE, "unknown", 0);
#else
f_allocImp( uiSize, &pvReturnPtr);
#endif
return( pvReturnPtr);
}
/****************************************************************************
Desc:
****************************************************************************/
void * XF_Base::operator new[](
FLMSIZET uiSize)
{
void * pvReturnPtr = NULL;
// NOTICE: You should be using f_new[] so that we can track memory leaks
#ifdef FLM_DEBUG
f_allocImp( uiSize, &pvReturnPtr, TRUE, "unknown", 0);
#else
f_allocImp( uiSize, &pvReturnPtr);
#endif
return( pvReturnPtr);
}
/****************************************************************************
Desc:
****************************************************************************/
#ifdef FLM_DEBUG
void * XF_Base::operator new(
FLMSIZET uiSize,
const char * pszFile,
int iLine)
{
void * pvReturnPtr = NULL;
f_allocImp( uiSize, &pvReturnPtr, TRUE, pszFile, iLine);
return( pvReturnPtr);
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
#ifdef FLM_DEBUG
void * XF_Base::operator new[](
FLMSIZET uiSize,
const char * pszFile,
int iLine)
{
void * pvReturnPtr = NULL;
f_allocImp( uiSize, &pvReturnPtr, TRUE, pszFile, iLine);
return( pvReturnPtr);
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
void XF_Base::operator delete(
void * ptr)
{
if( !ptr)
{
return;
}
f_freeImp( &ptr, TRUE);
}
/****************************************************************************
Desc:
****************************************************************************/
void XF_Base::operator delete[](
void * ptr)
{
if( !ptr)
{
return;
}
f_freeImp( &ptr, TRUE);
}
/****************************************************************************
Desc:
****************************************************************************/
#if defined( FLM_DEBUG) && !defined( FLM_WATCOM_NLM) && !defined( FLM_SOLARIS)
void XF_Base::operator delete(
void * ptr,
char *, // file
int) // line
{
if( !ptr)
{
return;
}
f_freeImp( &ptr, TRUE);
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
#if defined( FLM_DEBUG) && !defined( FLM_WATCOM_NLM) && !defined( FLM_SOLARIS)
void XF_Base::operator delete[](
void * ptr,
char *, // file
int) // line
{
if( !ptr)
{
return;
}
f_freeImp( &ptr, TRUE);
}
#endif
/************************************************************************
Desc:
*************************************************************************/
void * F_OSBase::operator new(
FLMSIZET uiSize)
{
return( os_malloc( uiSize));
}
/****************************************************************************
Desc:
****************************************************************************/
#ifdef FLM_DEBUG
void * F_OSBase::operator new(
FLMSIZET uiSize,
const char *, // pszFile,
int) // iLine)
{
return( os_malloc( uiSize));
}
#endif
/************************************************************************
Desc:
*************************************************************************/
void F_OSBase::operator delete(
void * ptr)
{
os_free( ptr);
}
/****************************************************************************
Desc:
****************************************************************************/
void F_OSBase::operator delete[](
void * ptr)
{
os_free( &ptr);
}
/****************************************************************************
Desc:
****************************************************************************/
#if defined( FLM_DEBUG) && !defined( FLM_WATCOM_NLM) && !defined( FLM_SOLARIS)
void F_OSBase::operator delete(
void * ptr,
const char *, // file
int) // line
{
os_free( &ptr);
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
#if defined( FLM_DEBUG) && !defined( FLM_WATCOM_NLM) && !defined( FLM_SOLARIS)
void F_OSBase::operator delete[](
void * ptr,
const char *, // file
int) // line
{
os_free( &ptr);
}
#endif