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.

267 lines
8.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "pch_tier0.h"
  8. #include "tier0/memblockhdr.h"
  9. #ifdef DBGFLAG_VALIDATE
  10. // we use malloc & free internally in our validation code; turn off the deprecation #defines
  11. #undef malloc
  12. #undef free
  13. //-----------------------------------------------------------------------------
  14. // Purpose: Constructor
  15. //-----------------------------------------------------------------------------
  16. CValidator::CValidator( )
  17. {
  18. m_pValObjectFirst = NULL;
  19. m_pValObjectLast = NULL;
  20. m_pValObjectCur = NULL;
  21. m_cpvOwned = 0;
  22. m_bMemLeaks = false;
  23. // Mark all memory blocks as unclaimed, prior to starting the validation process
  24. CMemBlockHdr *pMemBlockHdr = CMemBlockHdr::PMemBlockHdrFirst( );
  25. pMemBlockHdr = pMemBlockHdr->PMemBlockHdrNext( ); // Head is just a placeholder
  26. while ( NULL != pMemBlockHdr )
  27. {
  28. pMemBlockHdr->SetBClaimed( false );
  29. pMemBlockHdr = pMemBlockHdr->PMemBlockHdrNext( );
  30. }
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Purpose: Destructor
  34. //-----------------------------------------------------------------------------
  35. CValidator::~CValidator( )
  36. {
  37. CValObject *pValObject = m_pValObjectFirst;
  38. CValObject *pValObjectNext;
  39. while ( NULL != pValObject )
  40. {
  41. pValObjectNext = pValObject->PValObjectNext( );
  42. Destruct<CValObject> (pValObject);
  43. free( pValObject );
  44. pValObject = pValObjectNext;
  45. }
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Purpose: Call this each time you start a new Validate() function. It creates
  49. // a new CValObject to track the caller.
  50. // Input: pchType - The caller's type (typically a class name)
  51. // pvObj - The caller (typically an object pointer)
  52. // pchName - The caller's individual name (typically a member var of another class)
  53. //-----------------------------------------------------------------------------
  54. void CValidator::Push( tchar *pchType, void *pvObj, tchar *pchName )
  55. {
  56. // Create a new ValObject and add it to the linked list
  57. CValObject *pValObjectNew = (CValObject *) malloc( sizeof (CValObject ) );
  58. Construct<CValObject> (pValObjectNew);
  59. pValObjectNew->Init( pchType, pvObj, pchName, m_pValObjectCur, m_pValObjectLast );
  60. m_pValObjectLast = pValObjectNew;
  61. if ( NULL == m_pValObjectFirst )
  62. m_pValObjectFirst = pValObjectNew;
  63. // Make this the current object
  64. m_pValObjectCur = pValObjectNew;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose: Call this each time you end a Validate() function. It decrements
  68. // our current structure depth.
  69. //-----------------------------------------------------------------------------
  70. void CValidator::Pop( )
  71. {
  72. Assert( NULL != m_pValObjectCur );
  73. m_pValObjectCur = m_pValObjectCur->PValObjectParent( );
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Call this to register each memory block you own.
  77. // Input: pvMem - Memory block you own
  78. //-----------------------------------------------------------------------------
  79. void CValidator::ClaimMemory( void *pvMem )
  80. {
  81. if ( NULL == pvMem )
  82. return;
  83. // Mark the block as owned
  84. CMemBlockHdr *pMemBlockHdr = CMemBlockHdr::PMemBlockHdrFromPvUser( pvMem );
  85. pMemBlockHdr->CheckValid( );
  86. Assert( !pMemBlockHdr->BClaimed( ) );
  87. pMemBlockHdr->SetBClaimed( true );
  88. // Let the current object know about it
  89. Assert( NULL != m_pValObjectCur );
  90. m_pValObjectCur->ClaimMemoryBlock( pvMem );
  91. // Update our counter
  92. m_cpvOwned++;
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: We're done enumerating our objects. Perform any final calculations.
  96. //-----------------------------------------------------------------------------
  97. void CValidator::Finalize( void )
  98. {
  99. // Count our memory leaks
  100. CMemBlockHdr *pMemBlockHdr = CMemBlockHdr::PMemBlockHdrFirst( );
  101. pMemBlockHdr = pMemBlockHdr->PMemBlockHdrNext( );
  102. m_cpubLeaked = 0;
  103. m_cubLeaked = 0;
  104. while ( NULL != pMemBlockHdr )
  105. {
  106. if ( !pMemBlockHdr->BClaimed( ) )
  107. {
  108. m_cpubLeaked++;
  109. m_cubLeaked += pMemBlockHdr->CubUser( );
  110. m_bMemLeaks = true;
  111. }
  112. pMemBlockHdr = pMemBlockHdr->PMemBlockHdrNext( );
  113. }
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose: Render all reported objects to the console
  117. // Input: cubThreshold - Only render object whose children have at least
  118. // cubThreshold bytes allocated
  119. //-----------------------------------------------------------------------------
  120. void CValidator::RenderObjects( int cubThreshold )
  121. {
  122. // Walk our object list and render them all to the console
  123. CValObject *pValObject = m_pValObjectFirst;
  124. while ( NULL != pValObject )
  125. {
  126. if ( pValObject->CubMemTree( ) >= cubThreshold )
  127. {
  128. for ( int ich = 0; ich < pValObject->NLevel( ); ich++ )
  129. ConMsg( 2, _T(" ") );
  130. ConMsg( 2, _T("%s at 0x%x--> %d blocks = %d bytes\n"),
  131. pValObject->PchType( ), pValObject->PvObj( ), pValObject->CpubMemTree( ),
  132. pValObject->CubMemTree( ) );
  133. }
  134. pValObject = pValObject->PValObjectNext( );
  135. }
  136. // Dump a summary to the console
  137. ConMsg( 2, _T("Allocated:\t%d blocks\t%d bytes\n"), CpubAllocated( ), CubAllocated( ) );
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose: Render any discovered memory leaks to the console
  141. //-----------------------------------------------------------------------------
  142. void CValidator::RenderLeaks( void )
  143. {
  144. if ( m_bMemLeaks )
  145. ConMsg( 1, _T("\n") );
  146. // Render any leaked blocks to the console
  147. CMemBlockHdr *pMemBlockHdr = CMemBlockHdr::PMemBlockHdrFirst( );
  148. pMemBlockHdr = pMemBlockHdr->PMemBlockHdrNext( );
  149. while ( NULL != pMemBlockHdr )
  150. {
  151. if ( !pMemBlockHdr->BClaimed( ) )
  152. {
  153. ConMsg( 1, _T("Leaked mem block: Addr = 0x%x\tSize = %d\n"),
  154. pMemBlockHdr->PvUser( ), pMemBlockHdr->CubUser( ) );
  155. ConMsg( 1, _T("\tAlloc = %s, line %d\n"),
  156. pMemBlockHdr->PchFile( ), pMemBlockHdr->NLine( ) );
  157. }
  158. pMemBlockHdr = pMemBlockHdr->PMemBlockHdrNext( );
  159. }
  160. // Dump a summary to the console
  161. if ( 0 != m_cpubLeaked )
  162. ConMsg( 1, _T("!!!Leaked:\t%d blocks\t%d bytes\n"), m_cpubLeaked, m_cubLeaked );
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: Find the validator object associated with the given real object.
  166. //-----------------------------------------------------------------------------
  167. CValObject *CValidator::FindObject( void * pvObj )
  168. {
  169. CValObject *pValObject = m_pValObjectFirst;
  170. CValObject *pValObjectNext;
  171. while ( NULL != pValObject )
  172. {
  173. pValObjectNext = pValObject->PValObjectNext( );
  174. if( pvObj == pValObject->PvObj() )
  175. return pValObject;
  176. pValObject = pValObjectNext;
  177. }
  178. return NULL;
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Purpose: Diff one CValidator against another. Each Validator object is
  182. // tagged with whether it is new since the last snapshot or not.
  183. //-----------------------------------------------------------------------------
  184. void CValidator::DiffAgainst( CValidator *pOtherValidator ) // Removes any entries from this validator that are also present in the other.
  185. {
  186. // Render any leaked blocks to the console
  187. CValObject *pValObject = m_pValObjectFirst;
  188. CValObject *pValObjectNext;
  189. while ( NULL != pValObject )
  190. {
  191. pValObjectNext = pValObject->PValObjectNext( );
  192. pValObject->SetBNewSinceSnapshot( pOtherValidator->FindObject( pValObject->PvObj() ) == NULL );
  193. if( pValObject->BNewSinceSnapshot() && pValObject->CubMemTree( ) )
  194. {
  195. for ( int ich = 0; ich < pValObject->NLevel( ); ich++ )
  196. ConMsg( 2, _T(" ") );
  197. ConMsg( 2, _T("%s at 0x%x--> %d blocks = %d bytes\n"),
  198. pValObject->PchType( ), pValObject->PvObj( ), pValObject->CpubMemTree( ),
  199. pValObject->CubMemTree( ) );
  200. }
  201. pValObject = pValObjectNext;
  202. }
  203. }
  204. void CValidator::Validate( CValidator &validator, tchar *pchName )
  205. {
  206. validator.Push( _T("CValidator"), this, pchName );
  207. validator.ClaimMemory( this );
  208. // Render any leaked blocks to the console
  209. CValObject *pValObject = m_pValObjectFirst;
  210. CValObject *pValObjectNext;
  211. while ( NULL != pValObject )
  212. {
  213. pValObjectNext = pValObject->PValObjectNext( );
  214. validator.ClaimMemory( pValObject );
  215. pValObject = pValObjectNext;
  216. }
  217. validator.Pop();
  218. }
  219. #endif // DBGFLAG_VALIDATE