Team Fortress 2 Source Code as on 22/4/2020
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.

485 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Memory allocation!
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "pch_tier0.h"
  8. #ifndef STEAM
  9. #ifdef TIER0_VALIDATE_HEAP
  10. #include <malloc.h>
  11. #include "tier0/dbg.h"
  12. #include "tier0/memalloc.h"
  13. #include "mem_helpers.h"
  14. extern IMemAlloc *g_pActualAlloc;
  15. //-----------------------------------------------------------------------------
  16. // NOTE! This should never be called directly from leaf code
  17. // Just use new,delete,malloc,free etc. They will call into this eventually
  18. //-----------------------------------------------------------------------------
  19. class CValidateAlloc : public IMemAlloc
  20. {
  21. public:
  22. enum
  23. {
  24. HEAP_PREFIX_BUFFER_SIZE = 12,
  25. HEAP_SUFFIX_BUFFER_SIZE = 8,
  26. };
  27. CValidateAlloc();
  28. // Release versions
  29. virtual void *Alloc( size_t nSize );
  30. virtual void *Realloc( void *pMem, size_t nSize );
  31. virtual void Free( void *pMem );
  32. virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize );
  33. // Debug versions
  34. virtual void *Alloc( size_t nSize, const char *pFileName, int nLine );
  35. virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine );
  36. virtual void Free( void *pMem, const char *pFileName, int nLine );
  37. virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine );
  38. // Returns size of a particular allocation
  39. virtual size_t GetSize( void *pMem );
  40. // Force file + line information for an allocation
  41. virtual void PushAllocDbgInfo( const char *pFileName, int nLine );
  42. virtual void PopAllocDbgInfo();
  43. virtual long CrtSetBreakAlloc( long lNewBreakAlloc );
  44. virtual int CrtSetReportMode( int nReportType, int nReportMode );
  45. virtual int CrtIsValidHeapPointer( const void *pMem );
  46. virtual int CrtIsValidPointer( const void *pMem, unsigned int size, int access );
  47. virtual int CrtCheckMemory( void );
  48. virtual int CrtSetDbgFlag( int nNewFlag );
  49. virtual void CrtMemCheckpoint( _CrtMemState *pState );
  50. void* CrtSetReportFile( int nRptType, void* hFile );
  51. void* CrtSetReportHook( void* pfnNewHook );
  52. int CrtDbgReport( int nRptType, const char * szFile,
  53. int nLine, const char * szModule, const char * pMsg );
  54. virtual int heapchk();
  55. virtual void DumpStats() {}
  56. virtual void DumpStatsFileBase( char const *pchFileBase ) {}
  57. virtual bool IsDebugHeap()
  58. {
  59. return true;
  60. }
  61. virtual int GetVersion() { return MEMALLOC_VERSION; }
  62. virtual void CompactHeap();
  63. virtual MemAllocFailHandler_t SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler );
  64. virtual uint32 GetDebugInfoSize() { return 0; }
  65. virtual void SaveDebugInfo( void *pvDebugInfo ) { }
  66. virtual void RestoreDebugInfo( const void *pvDebugInfo ) {}
  67. virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) {}
  68. private:
  69. struct HeapPrefix_t
  70. {
  71. HeapPrefix_t *m_pPrev;
  72. HeapPrefix_t *m_pNext;
  73. int m_nSize;
  74. unsigned char m_Prefix[HEAP_PREFIX_BUFFER_SIZE];
  75. };
  76. struct HeapSuffix_t
  77. {
  78. unsigned char m_Suffix[HEAP_SUFFIX_BUFFER_SIZE];
  79. };
  80. private:
  81. // Returns the actual debug info
  82. void GetActualDbgInfo( const char *&pFileName, int &nLine );
  83. // Updates stats
  84. void RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime );
  85. void RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime );
  86. HeapSuffix_t *Suffix( HeapPrefix_t *pPrefix );
  87. void *AllocationStart( HeapPrefix_t *pBase );
  88. HeapPrefix_t *PrefixFromAllocation( void *pAlloc );
  89. const HeapPrefix_t *PrefixFromAllocation( const void *pAlloc );
  90. // Add to the list!
  91. void AddToList( HeapPrefix_t *pHeap, int nSize );
  92. // Remove from the list!
  93. void RemoveFromList( HeapPrefix_t *pHeap );
  94. // Validate the allocation
  95. bool ValidateAllocation( HeapPrefix_t *pHeap );
  96. private:
  97. HeapPrefix_t *m_pFirstAllocation;
  98. char m_pPrefixImage[HEAP_PREFIX_BUFFER_SIZE];
  99. char m_pSuffixImage[HEAP_SUFFIX_BUFFER_SIZE];
  100. };
  101. //-----------------------------------------------------------------------------
  102. // Singleton...
  103. //-----------------------------------------------------------------------------
  104. static CValidateAlloc s_ValidateAlloc;
  105. IMemAlloc *g_pMemAlloc = &s_ValidateAlloc;
  106. //-----------------------------------------------------------------------------
  107. // Constructor.
  108. //-----------------------------------------------------------------------------
  109. CValidateAlloc::CValidateAlloc()
  110. {
  111. m_pFirstAllocation = 0;
  112. memset( m_pPrefixImage, 0xBE, HEAP_PREFIX_BUFFER_SIZE );
  113. memset( m_pSuffixImage, 0xAF, HEAP_SUFFIX_BUFFER_SIZE );
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Accessors...
  117. //-----------------------------------------------------------------------------
  118. inline CValidateAlloc::HeapSuffix_t *CValidateAlloc::Suffix( HeapPrefix_t *pPrefix )
  119. {
  120. return reinterpret_cast<HeapSuffix_t *>( (unsigned char*)( pPrefix + 1 ) + pPrefix->m_nSize );
  121. }
  122. inline void *CValidateAlloc::AllocationStart( HeapPrefix_t *pBase )
  123. {
  124. return static_cast<void *>( pBase + 1 );
  125. }
  126. inline CValidateAlloc::HeapPrefix_t *CValidateAlloc::PrefixFromAllocation( void *pAlloc )
  127. {
  128. if ( !pAlloc )
  129. return NULL;
  130. return ((HeapPrefix_t*)pAlloc) - 1;
  131. }
  132. inline const CValidateAlloc::HeapPrefix_t *CValidateAlloc::PrefixFromAllocation( const void *pAlloc )
  133. {
  134. return ((const HeapPrefix_t*)pAlloc) - 1;
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Add to the list!
  138. //-----------------------------------------------------------------------------
  139. void CValidateAlloc::AddToList( HeapPrefix_t *pHeap, int nSize )
  140. {
  141. pHeap->m_pPrev = NULL;
  142. pHeap->m_pNext = m_pFirstAllocation;
  143. if ( m_pFirstAllocation )
  144. {
  145. m_pFirstAllocation->m_pPrev = pHeap;
  146. }
  147. pHeap->m_nSize = nSize;
  148. m_pFirstAllocation = pHeap;
  149. HeapSuffix_t *pSuffix = Suffix( pHeap );
  150. memcpy( pHeap->m_Prefix, m_pPrefixImage, HEAP_PREFIX_BUFFER_SIZE );
  151. memcpy( pSuffix->m_Suffix, m_pSuffixImage, HEAP_SUFFIX_BUFFER_SIZE );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Remove from the list!
  155. //-----------------------------------------------------------------------------
  156. void CValidateAlloc::RemoveFromList( HeapPrefix_t *pHeap )
  157. {
  158. if ( !pHeap )
  159. return;
  160. ValidateAllocation( pHeap );
  161. if ( pHeap->m_pPrev )
  162. {
  163. pHeap->m_pPrev->m_pNext = pHeap->m_pNext;
  164. }
  165. else
  166. {
  167. m_pFirstAllocation = pHeap->m_pNext;
  168. }
  169. if ( pHeap->m_pNext )
  170. {
  171. pHeap->m_pNext->m_pPrev = pHeap->m_pPrev;
  172. }
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Validate the allocation
  176. //-----------------------------------------------------------------------------
  177. bool CValidateAlloc::ValidateAllocation( HeapPrefix_t *pHeap )
  178. {
  179. HeapSuffix_t *pSuffix = Suffix( pHeap );
  180. bool bOk = true;
  181. if ( memcmp( pHeap->m_Prefix, m_pPrefixImage, HEAP_PREFIX_BUFFER_SIZE ) )
  182. {
  183. bOk = false;
  184. }
  185. if ( memcmp( pSuffix->m_Suffix, m_pSuffixImage, HEAP_SUFFIX_BUFFER_SIZE ) )
  186. {
  187. bOk = false;
  188. }
  189. if ( !bOk )
  190. {
  191. Warning("Memory trash detected in allocation %X!\n", (void*)(pHeap+1) );
  192. Assert( 0 );
  193. }
  194. return bOk;
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Release versions
  198. //-----------------------------------------------------------------------------
  199. void *CValidateAlloc::Alloc( size_t nSize )
  200. {
  201. Assert( heapchk() == _HEAPOK );
  202. Assert( CrtCheckMemory() );
  203. int nActualSize = nSize + sizeof(HeapPrefix_t) + sizeof(HeapSuffix_t);
  204. HeapPrefix_t *pHeap = (HeapPrefix_t*)g_pActualAlloc->Alloc( nActualSize );
  205. AddToList( pHeap, nSize );
  206. return AllocationStart( pHeap );
  207. }
  208. void *CValidateAlloc::Realloc( void *pMem, size_t nSize )
  209. {
  210. Assert( heapchk() == _HEAPOK );
  211. Assert( CrtCheckMemory() );
  212. HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  213. RemoveFromList( pHeap );
  214. int nActualSize = nSize + sizeof(HeapPrefix_t) + sizeof(HeapSuffix_t);
  215. pHeap = (HeapPrefix_t*)g_pActualAlloc->Realloc( pHeap, nActualSize );
  216. AddToList( pHeap, nSize );
  217. return AllocationStart( pHeap );
  218. }
  219. void CValidateAlloc::Free( void *pMem )
  220. {
  221. Assert( heapchk() == _HEAPOK );
  222. Assert( CrtCheckMemory() );
  223. HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  224. RemoveFromList( pHeap );
  225. g_pActualAlloc->Free( pHeap );
  226. }
  227. void *CValidateAlloc::Expand_NoLongerSupported( void *pMem, size_t nSize )
  228. {
  229. Assert( heapchk() == _HEAPOK );
  230. Assert( CrtCheckMemory() );
  231. HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  232. RemoveFromList( pHeap );
  233. int nActualSize = nSize + sizeof(HeapPrefix_t) + sizeof(HeapSuffix_t);
  234. pHeap = (HeapPrefix_t*)g_pActualAlloc->Expand_NoLongerSupported( pHeap, nActualSize );
  235. AddToList( pHeap, nSize );
  236. return AllocationStart( pHeap );
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Debug versions
  240. //-----------------------------------------------------------------------------
  241. void *CValidateAlloc::Alloc( size_t nSize, const char *pFileName, int nLine )
  242. {
  243. Assert( heapchk() == _HEAPOK );
  244. Assert( CrtCheckMemory() );
  245. int nActualSize = nSize + sizeof(HeapPrefix_t) + sizeof(HeapSuffix_t);
  246. HeapPrefix_t *pHeap = (HeapPrefix_t*)g_pActualAlloc->Alloc( nActualSize, pFileName, nLine );
  247. AddToList( pHeap, nSize );
  248. return AllocationStart( pHeap );
  249. }
  250. void *CValidateAlloc::Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine )
  251. {
  252. Assert( heapchk() == _HEAPOK );
  253. Assert( CrtCheckMemory() );
  254. HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  255. RemoveFromList( pHeap );
  256. int nActualSize = nSize + sizeof(HeapPrefix_t) + sizeof(HeapSuffix_t);
  257. pHeap = (HeapPrefix_t*)g_pActualAlloc->Realloc( pHeap, nActualSize, pFileName, nLine );
  258. AddToList( pHeap, nSize );
  259. return AllocationStart( pHeap );
  260. }
  261. void CValidateAlloc::Free( void *pMem, const char *pFileName, int nLine )
  262. {
  263. Assert( heapchk() == _HEAPOK );
  264. Assert( CrtCheckMemory() );
  265. HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  266. RemoveFromList( pHeap );
  267. g_pActualAlloc->Free( pHeap, pFileName, nLine );
  268. }
  269. void *CValidateAlloc::Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine )
  270. {
  271. Assert( heapchk() == _HEAPOK );
  272. Assert( CrtCheckMemory() );
  273. HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  274. RemoveFromList( pHeap );
  275. int nActualSize = nSize + sizeof(HeapPrefix_t) + sizeof(HeapSuffix_t);
  276. pHeap = (HeapPrefix_t*)g_pActualAlloc->Expand_NoLongerSupported( pHeap, nActualSize, pFileName, nLine );
  277. AddToList( pHeap, nSize );
  278. return AllocationStart( pHeap );
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Returns size of a particular allocation
  282. //-----------------------------------------------------------------------------
  283. size_t CValidateAlloc::GetSize( void *pMem )
  284. {
  285. if ( !pMem )
  286. return CalcHeapUsed();
  287. HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  288. return pHeap->m_nSize;
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Force file + line information for an allocation
  292. //-----------------------------------------------------------------------------
  293. void CValidateAlloc::PushAllocDbgInfo( const char *pFileName, int nLine )
  294. {
  295. g_pActualAlloc->PushAllocDbgInfo( pFileName, nLine );
  296. }
  297. void CValidateAlloc::PopAllocDbgInfo()
  298. {
  299. g_pActualAlloc->PopAllocDbgInfo( );
  300. }
  301. //-----------------------------------------------------------------------------
  302. // FIXME: Remove when we make our own heap! Crt stuff we're currently using
  303. //-----------------------------------------------------------------------------
  304. long CValidateAlloc::CrtSetBreakAlloc( long lNewBreakAlloc )
  305. {
  306. return g_pActualAlloc->CrtSetBreakAlloc( lNewBreakAlloc );
  307. }
  308. int CValidateAlloc::CrtSetReportMode( int nReportType, int nReportMode )
  309. {
  310. return g_pActualAlloc->CrtSetReportMode( nReportType, nReportMode );
  311. }
  312. int CValidateAlloc::CrtIsValidHeapPointer( const void *pMem )
  313. {
  314. const HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  315. return g_pActualAlloc->CrtIsValidHeapPointer( pHeap );
  316. }
  317. int CValidateAlloc::CrtIsValidPointer( const void *pMem, unsigned int size, int access )
  318. {
  319. const HeapPrefix_t *pHeap = PrefixFromAllocation( pMem );
  320. return g_pActualAlloc->CrtIsValidPointer( pHeap, size, access );
  321. }
  322. int CValidateAlloc::CrtCheckMemory( void )
  323. {
  324. return g_pActualAlloc->CrtCheckMemory( );
  325. }
  326. int CValidateAlloc::CrtSetDbgFlag( int nNewFlag )
  327. {
  328. return g_pActualAlloc->CrtSetDbgFlag( nNewFlag );
  329. }
  330. void CValidateAlloc::CrtMemCheckpoint( _CrtMemState *pState )
  331. {
  332. g_pActualAlloc->CrtMemCheckpoint( pState );
  333. }
  334. void* CValidateAlloc::CrtSetReportFile( int nRptType, void* hFile )
  335. {
  336. return g_pActualAlloc->CrtSetReportFile( nRptType, hFile );
  337. }
  338. void* CValidateAlloc::CrtSetReportHook( void* pfnNewHook )
  339. {
  340. return g_pActualAlloc->CrtSetReportHook( pfnNewHook );
  341. }
  342. int CValidateAlloc::CrtDbgReport( int nRptType, const char * szFile,
  343. int nLine, const char * szModule, const char * pMsg )
  344. {
  345. return g_pActualAlloc->CrtDbgReport( nRptType, szFile, nLine, szModule, pMsg );
  346. }
  347. int CValidateAlloc::heapchk()
  348. {
  349. bool bOk = true;
  350. // Validate the heap
  351. HeapPrefix_t *pHeap = m_pFirstAllocation;
  352. for( pHeap = m_pFirstAllocation; pHeap; pHeap = pHeap->m_pNext )
  353. {
  354. if ( !ValidateAllocation( pHeap ) )
  355. {
  356. bOk = false;
  357. }
  358. }
  359. #ifdef _WIN32
  360. return bOk ? _HEAPOK : 0;
  361. #elif POSIX
  362. return bOk;
  363. #else
  364. #error
  365. #endif
  366. }
  367. // Returns the actual debug info
  368. void CValidateAlloc::GetActualDbgInfo( const char *&pFileName, int &nLine )
  369. {
  370. g_pActualAlloc->GetActualDbgInfo( pFileName, nLine );
  371. }
  372. // Updates stats
  373. void CValidateAlloc::RegisterAllocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime )
  374. {
  375. g_pActualAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime );
  376. }
  377. void CValidateAlloc::RegisterDeallocation( const char *pFileName, int nLine, int nLogicalSize, int nActualSize, unsigned nTime )
  378. {
  379. g_pActualAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime );
  380. }
  381. void CValidateAlloc::CompactHeap()
  382. {
  383. g_pActualAlloc->CompactHeap();
  384. }
  385. MemAllocFailHandler_t CValidateAlloc::SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler )
  386. {
  387. return g_pActualAlloc->SetAllocFailHandler( pfnMemAllocFailHandler );
  388. }
  389. #endif // TIER0_VALIDATE_HEAP
  390. #endif // STEAM