Counter Strike : Global Offensive Source Code
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.

498 lines
14 KiB

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