Leaked source code of windows server 2003
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.

268 lines
5.4 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. Mem.cxx
  6. Abstract:
  7. Memory manipulations
  8. Author:
  9. Albert Ting (AlbertT) 20-May-1994
  10. Revision History:
  11. --*/
  12. #include "spllibp.hxx"
  13. #pragma hdrstop
  14. HANDLE ghMemHeap;
  15. #if defined( CHECKMEM ) || DBG
  16. LONG gcbMem = 0;
  17. #endif
  18. #if DBG
  19. HANDLE ghDbgMemHeap;
  20. VBackTrace* gpbtAlloc;
  21. VBackTrace* gpbtFree;
  22. /*++
  23. Memory fail test code
  24. This is test code (checked builds only) that fails memory allocations
  25. at regular intervals. It helps detect cases where we are not checking
  26. memory return errors.
  27. Every gcAlloc allocations, it will try to fail. However, if it detects
  28. that it has failed at that backtrace in the past, it will not fail
  29. and try to fail at the next allocation.
  30. Once it has failed, the counter is reset.
  31. To enable, set gbAllocFail to 1 (usually from the debugger).
  32. If you find an allocation and want to fail at it again, set the
  33. gAllocFailHash to the hash value of the failure, then also
  34. set gAllocFailHashAction to 1 (for fail) or 2 (for break and fail).
  35. gbAllocFail controls whether the alloc fail is enabled.
  36. gcAlloc is the current count of allocs.
  37. gcAllocFail indicates how often we fail (every gcAllocFail allocs).
  38. --*/
  39. BOOL gbAllocFail = FALSE;
  40. LONG gcAlloc = 0;
  41. LONG gcAllocFail = 0x20;
  42. ULONG gAllocFailHash = 0;
  43. enum EAllocFailHashAction {
  44. kIgnore = 0,
  45. kFail = 1,
  46. kBreakFail = 2
  47. };
  48. EAllocFailHashAction gAllocFailHashAction = kIgnore;
  49. PVOID
  50. DbgAllocMem(
  51. UINT cbSize
  52. )
  53. {
  54. return HeapAlloc( ghDbgMemHeap, 0, cbSize );
  55. }
  56. VOID
  57. DbgFreeMem(
  58. PVOID pMem
  59. )
  60. {
  61. if( pMem ){
  62. HeapFree( ghDbgMemHeap, 0, pMem );
  63. }
  64. }
  65. #endif
  66. PVOID
  67. AllocMem(
  68. UINT cbSize
  69. )
  70. /*++
  71. Routine Description:
  72. Allocates memory. If CHECKMEM is defined, adds tail guard.
  73. Arguments:
  74. Return Value:
  75. --*/
  76. {
  77. #if defined( CHECKMEM ) || DBG
  78. PULONG_PTR pMem;
  79. UINT cbNew;
  80. cbNew = DWordAlign(cbSize+3*sizeof(*pMem));
  81. pMem = (PULONG_PTR)HeapAlloc( ghMemHeap, 0, cbNew );
  82. if (!pMem) {
  83. //
  84. // HeapAlloc either raises an exception or returns NULL, but does not set the last error
  85. //
  86. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  87. return NULL;
  88. }
  89. FillMemory(pMem, cbNew, 0x83);
  90. pMem[0] = cbSize;
  91. #if DBG
  92. HANDLE hData;
  93. ULONG Hash = 0;
  94. hData = gpbtAlloc ?
  95. gpbtAlloc->hCapture( (ULONG_PTR)&pMem[2], cbSize, 0, &Hash ) :
  96. NULL;
  97. pMem[1] = reinterpret_cast<ULONG_PTR>( hData );
  98. //
  99. // Test if what happens if out of memory failures
  100. // occur.
  101. //
  102. if( gbAllocFail && gpbtAlloc){
  103. BOOL bHashCase;
  104. bHashCase = ( Hash == gAllocFailHash ) &&
  105. ( gAllocFailHashAction != kIgnore );
  106. if( bHashCase ||
  107. ( InterlockedCompareExchange( &gcAlloc, 0, 0 ) == 0 )){
  108. BOOL bBreak = bHashCase && ( gAllocFailHashAction == kBreakFail );
  109. PLONG plCount;
  110. plCount = gpbtAlloc->plGetCount( hData );
  111. //
  112. // Counter started at -1, so if it is 0 now, then fail
  113. // the allocation.
  114. //
  115. if( bBreak ||
  116. ( plCount && InterlockedIncrement( plCount ) == 0 )){
  117. gpbtAlloc->hCapture( 0, cbSize );
  118. HeapFree( ghMemHeap, 0, (PVOID)pMem );
  119. pMem = NULL;
  120. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  121. //
  122. // Reset the counter to the negative number.
  123. //
  124. InterlockedExchangeAdd( &gcAlloc, -gcAllocFail );
  125. if( bBreak ){
  126. OutputDebugStringA( "Reached AllocFail Hash.\n" );
  127. DebugBreak();
  128. }
  129. return NULL;
  130. }
  131. } else {
  132. //
  133. // We didn't reach zero. Increment the count.
  134. //
  135. InterlockedIncrement( &gcAlloc );
  136. }
  137. }
  138. #endif
  139. InterlockedExchangeAdd( &gcbMem, cbNew );
  140. *(PDWORD)((PBYTE)pMem + cbNew - sizeof(ULONG_PTR)) = 0xdeadbeef;
  141. return (PVOID)(pMem+2);
  142. #else
  143. VOID *pMem = HeapAlloc(ghMemHeap, 0, cbSize);
  144. if (!pMem)
  145. {
  146. //
  147. // HeapAlloc either raises an exception or returns NULL, but does not set the last error
  148. //
  149. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  150. }
  151. return pMem;
  152. #endif
  153. }
  154. VOID
  155. FreeMem(
  156. PVOID pMem
  157. )
  158. {
  159. if( !pMem ){
  160. return;
  161. }
  162. #if defined( CHECKMEM ) || DBG
  163. DWORD cbSize;
  164. PULONG_PTR pNewMem;
  165. pNewMem = (PULONG_PTR)pMem;
  166. pNewMem -= 2;
  167. cbSize = (DWORD)*pNewMem;
  168. InterlockedExchangeAdd( &gcbMem, -(LONG)cbSize );
  169. if (*(PDWORD)((PBYTE)pMem + DWordAlign(cbSize)) != 0xdeadbeef) {
  170. DBGMSG( DBG_ERROR,
  171. ( "Corrupt Memory: %x size = 0x%x\n",
  172. pMem,
  173. cbSize ));
  174. } else {
  175. FillMemory(pNewMem, cbSize, 0x65);
  176. HeapFree( ghMemHeap, 0, (PVOID)pNewMem );
  177. #if DBG
  178. if( gpbtFree ){
  179. gpbtFree->hCapture( (ULONG_PTR)pMem, cbSize );
  180. }
  181. #endif
  182. }
  183. #else
  184. HeapFree( ghMemHeap, 0, (PVOID)pMem );
  185. #endif
  186. }