578 lines
No EOL
12 KiB
C++
578 lines
No EOL
12 KiB
C++
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Insert this file into all projects using the memory system
|
|
// It will cause that project to use the shader memory allocator
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
|
|
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
|
|
|
|
#undef PROTECTED_THINGS_ENABLE // allow use of _vsnprintf
|
|
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
#define WIN_32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
|
|
|
|
#include "tier0/dbg.h"
|
|
#include "tier0/memalloc.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "memdbgoff.h"
|
|
|
|
// Tags this DLL as debug
|
|
#if _DEBUG
|
|
DLL_EXPORT void BuiltDebug() {}
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
// ARG: crtdbg is necessary for certain definitions below,
|
|
// but it also redefines malloc as a macro in release.
|
|
// To disable this, we gotta define _DEBUG before including it.. BLEAH!
|
|
#define _DEBUG 1
|
|
#include "crtdbg.h"
|
|
#ifdef NDEBUG
|
|
#undef _DEBUG
|
|
#endif
|
|
|
|
// Turn this back off in release mode.
|
|
#ifdef NDEBUG
|
|
#undef _DEBUG
|
|
#endif
|
|
#elif _LINUX
|
|
#define __cdecl
|
|
#endif
|
|
|
|
|
|
#if defined(_WIN32) && !defined(_XBOX)
|
|
const char *MakeModuleFileName()
|
|
{
|
|
if ( g_pMemAlloc->IsDebugHeap() )
|
|
{
|
|
char *pszModuleName = (char *)HeapAlloc( GetProcessHeap(), 0, MAX_PATH ); // small leak, debug only
|
|
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
static int dummy;
|
|
VirtualQuery( &dummy, &mbi, sizeof(mbi) );
|
|
|
|
GetModuleFileName( reinterpret_cast<HMODULE>(mbi.AllocationBase), pszModuleName, MAX_PATH );
|
|
char *pDot = strrchr( pszModuleName, '.' );
|
|
if ( pDot )
|
|
{
|
|
char *pSlash = strrchr( pszModuleName, '\\' );
|
|
if ( pSlash )
|
|
{
|
|
pszModuleName = pSlash + 1;
|
|
*pDot = 0;
|
|
}
|
|
}
|
|
|
|
return pszModuleName;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void *AllocUnattributed( size_t nSize )
|
|
{
|
|
static const char *pszOwner = MakeModuleFileName();
|
|
|
|
if ( !pszOwner )
|
|
return g_pMemAlloc->Alloc(nSize);
|
|
else
|
|
return g_pMemAlloc->Alloc(nSize, pszOwner, 0);
|
|
}
|
|
|
|
static void *ReallocUnattributed( void *pMem, size_t nSize )
|
|
{
|
|
static const char *pszOwner = MakeModuleFileName();
|
|
|
|
if ( !pszOwner )
|
|
return g_pMemAlloc->Realloc(pMem, nSize);
|
|
else
|
|
return g_pMemAlloc->Realloc(pMem, nSize, pszOwner, 0);
|
|
}
|
|
|
|
#else
|
|
#define MakeModuleFileName() NULL
|
|
inline void *AllocUnattributed( size_t nSize )
|
|
{
|
|
return g_pMemAlloc->Alloc(nSize);
|
|
}
|
|
|
|
inline void *ReallocUnattributed( void *pMem, size_t nSize )
|
|
{
|
|
return g_pMemAlloc->Realloc(pMem, nSize);
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Standard functions in the CRT that we're going to override to call our allocator
|
|
//-----------------------------------------------------------------------------
|
|
#if defined(_WIN32) && !defined(_STATIC_LINKED)
|
|
// this magic only works under win32
|
|
// under linux this malloc() overrides the libc malloc() and so we
|
|
// end up in a recursion (as g_pMemAlloc->Alloc() calls malloc)
|
|
#if _MSC_VER >= 1400
|
|
#define ALLOC_CALL _CRTNOALIAS _CRTRESTRICT
|
|
#define FREE_CALL _CRTNOALIAS
|
|
#else
|
|
#define ALLOC_CALL
|
|
#define FREE_CALL
|
|
#endif
|
|
|
|
extern "C"
|
|
{
|
|
|
|
ALLOC_CALL void *malloc( size_t nSize )
|
|
{
|
|
return AllocUnattributed( nSize );
|
|
}
|
|
|
|
FREE_CALL void free( void *pMem )
|
|
{
|
|
g_pMemAlloc->Free(pMem);
|
|
}
|
|
|
|
ALLOC_CALL void *realloc( void *pMem, size_t nSize )
|
|
{
|
|
return ReallocUnattributed( pMem, nSize );
|
|
}
|
|
|
|
ALLOC_CALL void *calloc( size_t nCount, size_t nElementSize )
|
|
{
|
|
void *pMem = AllocUnattributed( nElementSize * nCount );
|
|
memset(pMem, 0, nElementSize * nCount);
|
|
return pMem;
|
|
}
|
|
|
|
} // end extern "C"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Non-standard MSVC functions that we're going to override to call our allocator
|
|
//-----------------------------------------------------------------------------
|
|
extern "C"
|
|
{
|
|
|
|
void *_malloc_base( size_t nSize )
|
|
{
|
|
return AllocUnattributed( nSize );
|
|
}
|
|
|
|
void _free_base( void *pMem )
|
|
{
|
|
g_pMemAlloc->Free(pMem);
|
|
}
|
|
|
|
void *_realloc_base( void *pMem, size_t nSize )
|
|
{
|
|
return ReallocUnattributed( pMem, nSize );
|
|
}
|
|
|
|
int _heapchk()
|
|
{
|
|
return g_pMemAlloc->heapchk();
|
|
}
|
|
|
|
int _heapmin()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
size_t _msize( void *pMem )
|
|
{
|
|
return g_pMemAlloc->GetSize(pMem);
|
|
}
|
|
|
|
size_t msize( void *pMem )
|
|
{
|
|
return g_pMemAlloc->GetSize(pMem);
|
|
}
|
|
|
|
void *__cdecl _heap_alloc( size_t nSize )
|
|
{
|
|
return AllocUnattributed( nSize );
|
|
}
|
|
|
|
void *__cdecl _nh_malloc( size_t nSize, int )
|
|
{
|
|
return AllocUnattributed( nSize );
|
|
}
|
|
|
|
void *__cdecl _expand( void *pMem, size_t nSize )
|
|
{
|
|
Assert( 0 );
|
|
return NULL;
|
|
}
|
|
|
|
unsigned int _amblksiz = 16; //BYTES_PER_PARA;
|
|
|
|
size_t __cdecl _get_sbh_threshold( void )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int __cdecl _set_sbh_threshold( size_t )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int __cdecl _heapadd( void *, size_t )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int __cdecl _heapset( unsigned int )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t __cdecl _heapused( size_t *, size_t * )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
int __cdecl _heapwalk( _HEAPINFO * )
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
} // end extern "C"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Debugging functions that we're going to override to call our allocator
|
|
// NOTE: These have to be here for release + debug builds in case we
|
|
// link to a debug static lib!!!
|
|
//-----------------------------------------------------------------------------
|
|
|
|
extern "C"
|
|
{
|
|
|
|
void *malloc_db( size_t nSize, const char *pFileName, int nLine )
|
|
{
|
|
return g_pMemAlloc->Alloc(nSize, pFileName, nLine);
|
|
}
|
|
|
|
void free_db( void *pMem, const char *pFileName, int nLine )
|
|
{
|
|
g_pMemAlloc->Free(pMem, pFileName, nLine);
|
|
}
|
|
|
|
void *realloc_db( void *pMem, size_t nSize, const char *pFileName, int nLine )
|
|
{
|
|
return g_pMemAlloc->Realloc(pMem, nSize, pFileName, nLine);
|
|
}
|
|
|
|
} // end extern "C"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// These methods are standard MSVC heap initialization + shutdown methods
|
|
//-----------------------------------------------------------------------------
|
|
extern "C"
|
|
{
|
|
|
|
int __cdecl _heap_init()
|
|
{
|
|
return g_pMemAlloc != NULL;
|
|
}
|
|
|
|
void __cdecl _heap_term()
|
|
{
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Prevents us from using an inappropriate new or delete method,
|
|
// ensures they are here even when linking against debug or release static libs
|
|
//-----------------------------------------------------------------------------
|
|
#ifndef NO_MEMOVERRIDE_NEW_DELETE
|
|
void *__cdecl operator new( unsigned int nSize )
|
|
{
|
|
return AllocUnattributed( nSize );
|
|
}
|
|
|
|
void *__cdecl operator new( unsigned int nSize, int nBlockUse, const char *pFileName, int nLine )
|
|
{
|
|
return g_pMemAlloc->Alloc(nSize, pFileName, nLine);
|
|
}
|
|
|
|
void __cdecl operator delete( void *pMem )
|
|
{
|
|
g_pMemAlloc->Free( pMem );
|
|
}
|
|
|
|
void *__cdecl operator new[] ( unsigned int nSize )
|
|
{
|
|
return AllocUnattributed( nSize );
|
|
}
|
|
|
|
void *__cdecl operator new[] ( unsigned int nSize, int nBlockUse, const char *pFileName, int nLine )
|
|
{
|
|
return g_pMemAlloc->Alloc(nSize, pFileName, nLine);
|
|
}
|
|
|
|
void __cdecl operator delete[] ( void *pMem )
|
|
{
|
|
g_pMemAlloc->Free( pMem );
|
|
}
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Override some debugging allocation methods in MSVC
|
|
// NOTE: These have to be here for release + debug builds in case we
|
|
// link to a debug static lib!!!
|
|
//-----------------------------------------------------------------------------
|
|
#ifndef _STATIC_LINKED
|
|
#ifdef _WIN32
|
|
|
|
// This here just hides the internal file names, etc of allocations
|
|
// made in the c runtime library
|
|
#define CRT_INTERNAL_FILE_NAME "C-runtime internal"
|
|
|
|
class CAttibCRT
|
|
{
|
|
public:
|
|
CAttibCRT(int nBlockUse) : m_nBlockUse(nBlockUse)
|
|
{
|
|
if (m_nBlockUse == _CRT_BLOCK)
|
|
{
|
|
g_pMemAlloc->PushAllocDbgInfo(CRT_INTERNAL_FILE_NAME, 0);
|
|
}
|
|
}
|
|
|
|
~CAttibCRT()
|
|
{
|
|
if (m_nBlockUse == _CRT_BLOCK)
|
|
{
|
|
g_pMemAlloc->PopAllocDbgInfo();
|
|
}
|
|
}
|
|
|
|
private:
|
|
int m_nBlockUse;
|
|
};
|
|
|
|
|
|
#define AttribIfCrt() CAttibCRT _attrib(nBlockUse)
|
|
#elif defined(_LINUX)
|
|
#define AttribIfCrt()
|
|
#endif // _WIN32
|
|
|
|
|
|
extern "C"
|
|
{
|
|
|
|
void *__cdecl _nh_malloc_dbg( size_t nSize, int nFlag, int nBlockUse,
|
|
const char *pFileName, int nLine )
|
|
{
|
|
AttribIfCrt();
|
|
return g_pMemAlloc->Alloc(nSize, pFileName, nLine);
|
|
}
|
|
|
|
void *__cdecl _malloc_dbg( size_t nSize, int nBlockUse,
|
|
const char *pFileName, int nLine )
|
|
{
|
|
AttribIfCrt();
|
|
return g_pMemAlloc->Alloc(nSize, pFileName, nLine);
|
|
}
|
|
|
|
void *__cdecl _calloc_dbg( size_t nNum, size_t nSize, int nBlockUse,
|
|
const char *pFileName, int nLine )
|
|
{
|
|
AttribIfCrt();
|
|
void *pMem = g_pMemAlloc->Alloc(nSize * nNum, pFileName, nLine);
|
|
memset(pMem, 0, nSize * nNum);
|
|
return pMem;
|
|
}
|
|
|
|
void *__cdecl _realloc_dbg( void *pMem, size_t nNewSize, int nBlockUse,
|
|
const char *pFileName, int nLine )
|
|
{
|
|
AttribIfCrt();
|
|
return g_pMemAlloc->Realloc(pMem, nNewSize, pFileName, nLine);
|
|
}
|
|
|
|
void *__cdecl _expand_dbg( void *pMem, size_t nNewSize, int nBlockUse,
|
|
const char *pFileName, int nLine )
|
|
{
|
|
Assert( 0 );
|
|
return NULL;
|
|
}
|
|
|
|
void __cdecl _free_dbg( void *pMem, int nBlockUse )
|
|
{
|
|
AttribIfCrt();
|
|
g_pMemAlloc->Free(pMem);
|
|
}
|
|
|
|
size_t __cdecl _msize_dbg( void *pMem, int nBlockUse )
|
|
{
|
|
#ifdef _WIN32
|
|
return _msize(pMem);
|
|
#elif _LINUX
|
|
Assert( "_msize_dbg unsupported" );
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
} // end extern "C"
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Override some the _CRT debugging allocation methods in MSVC
|
|
//-----------------------------------------------------------------------------
|
|
#ifdef _WIN32
|
|
|
|
extern "C"
|
|
{
|
|
|
|
int _CrtDumpMemoryLeaks(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
_CRT_DUMP_CLIENT _CrtSetDumpClient( _CRT_DUMP_CLIENT dumpClient )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
int _CrtSetDbgFlag( int nNewFlag )
|
|
{
|
|
return g_pMemAlloc->CrtSetDbgFlag( nNewFlag );
|
|
}
|
|
|
|
long _crtBreakAlloc; /* Break on this allocation */
|
|
int _crtDbgFlag = _CRTDBG_ALLOC_MEM_DF;
|
|
|
|
void __cdecl _CrtSetDbgBlockType( void *pMem, int nBlockUse )
|
|
{
|
|
DebuggerBreak();
|
|
}
|
|
|
|
_CRT_ALLOC_HOOK __cdecl _CrtSetAllocHook( _CRT_ALLOC_HOOK pfnNewHook )
|
|
{
|
|
DebuggerBreak();
|
|
return NULL;
|
|
}
|
|
|
|
long __cdecl _CrtSetBreakAlloc( long lNewBreakAlloc )
|
|
{
|
|
return g_pMemAlloc->CrtSetBreakAlloc( lNewBreakAlloc );
|
|
}
|
|
|
|
int __cdecl _CrtIsValidHeapPointer( const void *pMem )
|
|
{
|
|
return g_pMemAlloc->CrtIsValidHeapPointer( pMem );
|
|
}
|
|
|
|
int __cdecl _CrtIsValidPointer( const void *pMem, unsigned int size, int access )
|
|
{
|
|
return g_pMemAlloc->CrtIsValidPointer( pMem, size, access );
|
|
}
|
|
|
|
int __cdecl _CrtCheckMemory( void )
|
|
{
|
|
// FIXME: Remove this when we re-implement the heap
|
|
return g_pMemAlloc->CrtCheckMemory( );
|
|
}
|
|
|
|
int __cdecl _CrtIsMemoryBlock( const void *pMem, unsigned int nSize,
|
|
long *plRequestNumber, char **ppFileName, int *pnLine )
|
|
{
|
|
DebuggerBreak();
|
|
return 1;
|
|
}
|
|
|
|
int __cdecl _CrtMemDifference( _CrtMemState *pState, const _CrtMemState * oldState, const _CrtMemState * newState )
|
|
{
|
|
DebuggerBreak();
|
|
return FALSE;
|
|
}
|
|
|
|
void __cdecl _CrtMemDumpStatistics( const _CrtMemState *pState )
|
|
{
|
|
DebuggerBreak();
|
|
}
|
|
|
|
void __cdecl _CrtMemCheckpoint( _CrtMemState *pState )
|
|
{
|
|
// FIXME: Remove this when we re-implement the heap
|
|
g_pMemAlloc->CrtMemCheckpoint( pState );
|
|
}
|
|
|
|
void __cdecl _CrtMemDumpAllObjectsSince( const _CrtMemState *pState )
|
|
{
|
|
DebuggerBreak();
|
|
}
|
|
|
|
void __cdecl _CrtDoForAllClientObjects( void (*pfn)(void *, void *), void * pContext )
|
|
{
|
|
DebuggerBreak();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Methods in dbgrpt.cpp
|
|
//-----------------------------------------------------------------------------
|
|
long _crtAssertBusy = -1;
|
|
|
|
int __cdecl _CrtSetReportMode( int nReportType, int nReportMode )
|
|
{
|
|
return g_pMemAlloc->CrtSetReportMode( nReportType, nReportMode );
|
|
}
|
|
|
|
_HFILE __cdecl _CrtSetReportFile( int nRptType, _HFILE hFile )
|
|
{
|
|
return (_HFILE)g_pMemAlloc->CrtSetReportFile( nRptType, hFile );
|
|
}
|
|
|
|
_CRT_REPORT_HOOK __cdecl _CrtSetReportHook( _CRT_REPORT_HOOK pfnNewHook )
|
|
{
|
|
return (_CRT_REPORT_HOOK)g_pMemAlloc->CrtSetReportHook( pfnNewHook );
|
|
}
|
|
|
|
int __cdecl _CrtDbgReport( int nRptType, const char * szFile,
|
|
int nLine, const char * szModule, const char * szFormat, ... )
|
|
{
|
|
static char output[1024];
|
|
va_list args;
|
|
va_start( args, szFormat );
|
|
_vsnprintf( output, sizeof( output )-1, szFormat, args );
|
|
va_end( args );
|
|
|
|
return g_pMemAlloc->CrtDbgReport( nRptType, szFile, nLine, szModule, output );
|
|
}
|
|
|
|
int __cdecl _CrtReportBlockType(const void * pUserData)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
} // end extern "C"
|
|
#endif // _WIN32
|
|
|
|
// Most files include this file, so when it's used it adds an extra .ValveDbg section,
|
|
// to help identify debug binaries.
|
|
#ifdef _WIN32
|
|
#ifndef NDEBUG // _DEBUG
|
|
#pragma data_seg("ValveDBG")
|
|
volatile const char* DBG = "*** DEBUG STUB ***";
|
|
#endif
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif // !STEAM && !NO_MALLOC_OVERRIDE
|