Source code of Windows XP (NT5)
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.

491 lines
11 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. Module Name:
  4. memory.cxx
  5. Abstract:
  6. This file contains the new and delete routines for memory management in
  7. the RPC runtime. Rather than using the memory management provided by the
  8. C++ system we'll use the system allocator.
  9. Revision History:
  10. mikemon ??-??-?? Beginning of time (at least for this file).
  11. mikemon 12-31-90 Upgraded the comments.
  12. mariogo 04-24-96 Rewrite to unify platforms, behavior and performance.
  13. --*/
  14. #include <precomp.hxx>
  15. #include <ntlsa.h> // definitions for LSA allocation routines
  16. HANDLE hRpcHeap = 0;
  17. unsigned int DebugFlags = 0;
  18. #define RPC_FAIL_ALLOCATIONS 0x00000001
  19. #define NO_HEAP_SLOWDOWN
  20. PLSA_ALLOCATE_PRIVATE_HEAP LsaAlloc = NULL;
  21. PLSA_FREE_PRIVATE_HEAP LsaFree = NULL;
  22. inline void *AllocWrapper(size_t size)
  23. {
  24. void *pobj;
  25. if( !LsaAlloc )
  26. {
  27. pobj = HeapAlloc(hRpcHeap, 0, size);
  28. }
  29. else
  30. {
  31. pobj = LsaAlloc( size );
  32. }
  33. LogEvent(SU_HEAP, EV_CREATE, pobj, hRpcHeap, size, TRUE, 3);
  34. return pobj;
  35. }
  36. inline void FreeWrapper(void *pobj)
  37. {
  38. LogEvent(SU_HEAP, EV_DELETE, pobj, hRpcHeap, 0, TRUE, 3);
  39. if( !LsaFree )
  40. {
  41. HeapFree(hRpcHeap, 0, pobj);
  42. }
  43. else
  44. {
  45. LsaFree( pobj );
  46. }
  47. }
  48. int fHeapInitialized = 0;
  49. int fBufferCacheInitialized = 0;
  50. BOOL fMaybeLsa = FALSE;
  51. #ifndef DEBUGRPC
  52. void *
  53. __cdecl
  54. operator new (
  55. IN size_t size
  56. )
  57. {
  58. return(AllocWrapper(size));
  59. }
  60. void
  61. __cdecl
  62. operator delete (
  63. IN void * obj
  64. )
  65. {
  66. FreeWrapper(obj);
  67. }
  68. int InitializeRpcAllocator(void)
  69. {
  70. HMODULE hLsa;
  71. if (0 == fHeapInitialized)
  72. {
  73. if (RpcpStringCompare(FastGetImageBaseName(), L"lsass.exe") == 0)
  74. {
  75. fMaybeLsa = TRUE;
  76. if (gfServerPlatform)
  77. {
  78. // if this looks like lsa on a server box
  79. hLsa = GetModuleHandle(L"lsasrv.dll");
  80. if (hLsa)
  81. {
  82. //
  83. // use LSA for FRE build (per KamenM request).
  84. //
  85. LsaAlloc = (PLSA_ALLOCATE_PRIVATE_HEAP)GetProcAddress(hLsa, "LsaIAllocateHeap");
  86. LsaFree = (PLSA_FREE_PRIVATE_HEAP)GetProcAddress(hLsa, "LsaIFreeHeap");
  87. if( LsaAlloc == NULL || LsaFree == NULL )
  88. {
  89. LsaAlloc = NULL;
  90. LsaFree = NULL;
  91. }
  92. }
  93. }
  94. }
  95. if (hRpcHeap == 0)
  96. hRpcHeap = RtlProcessHeap();
  97. fHeapInitialized = 1;
  98. }
  99. if (0 == fBufferCacheInitialized)
  100. {
  101. RPC_STATUS status = RPC_S_OK;
  102. gBufferCache = new BCACHE(status);
  103. if ( 0 == gBufferCache
  104. || status != RPC_S_OK )
  105. {
  106. return(RPC_S_OUT_OF_MEMORY);
  107. }
  108. fBufferCacheInitialized = TRUE;
  109. }
  110. return(RPC_S_OK);
  111. }
  112. int
  113. RpcpCheckHeap (
  114. void
  115. )
  116. // Allow some checked compenents to be linked into a free memory.cxx.
  117. {
  118. return 0;
  119. }
  120. #else // ******************** DEBUG ********************
  121. #ifdef NO_HEAP_SLOWDOWN
  122. int fMemoryCheck = 0;
  123. #else
  124. int fMemoryCheck = 1;
  125. #endif
  126. CRITICAL_SECTION RpcHeapLock;
  127. int InitializeRpcAllocator(void)
  128. /*++
  129. Routine Description:
  130. Called during RPC initialization. This function must can by one
  131. thread at a time. Sets the heap handle for debugging.
  132. Maybe called more then once if this (or a later step) of RPC
  133. initialization fails.
  134. --*/
  135. {
  136. if (0 == fHeapInitialized)
  137. {
  138. if (RpcpStringCompare(FastGetImageBaseName(), L"lsass.exe") == 0)
  139. {
  140. fMaybeLsa = TRUE;
  141. }
  142. if (0 == hRpcHeap)
  143. {
  144. hRpcHeap = RtlCreateHeap( HEAP_GROWABLE
  145. | HEAP_TAIL_CHECKING_ENABLED
  146. | HEAP_FREE_CHECKING_ENABLED
  147. | HEAP_CLASS_1,
  148. 0,
  149. 16 * 1024 - 512,
  150. 0,
  151. 0,
  152. 0
  153. );
  154. }
  155. if (hRpcHeap)
  156. {
  157. if (0 == RtlInitializeCriticalSectionAndSpinCount(&RpcHeapLock, PREALLOCATE_EVENT_MASK))
  158. {
  159. fHeapInitialized = 1;
  160. }
  161. }
  162. if (0 == fHeapInitialized )
  163. {
  164. return(RPC_S_OUT_OF_MEMORY);
  165. }
  166. }
  167. if (0 == fBufferCacheInitialized)
  168. {
  169. RPC_STATUS status = RPC_S_OK;
  170. gBufferCache = new BCACHE(status);
  171. if ( 0 == gBufferCache
  172. || status != RPC_S_OK )
  173. {
  174. return(RPC_S_OUT_OF_MEMORY);
  175. }
  176. fBufferCacheInitialized = TRUE;
  177. }
  178. return(RPC_S_OK);
  179. }
  180. #define RPC_GUARD 0xA1
  181. typedef struct _RPC_MEMORY_BLOCK
  182. {
  183. // First,forward and backward links to other RPC heap allocations.
  184. // These are first allow easy debugging with the dl command
  185. struct _RPC_MEMORY_BLOCK *next;
  186. struct _RPC_MEMORY_BLOCK *previous;
  187. // Specifies the size of the block of memory in bytes.
  188. unsigned long size;
  189. // Thread id of allocator
  190. unsigned long tid;
  191. void * AllocStackTrace[4];
  192. // (Pad to make header 0 mod 8) 0 when allocated, 0xF0F0F0F0 when freed.
  193. unsigned long free;
  194. // Reserve an extra 4 bytes as the front guard of each block.
  195. unsigned char frontguard[4];
  196. // Data will appear here. Note that the header must be 0 mod 8.
  197. // Reserve an extra 4 bytes as the rear guard of each block.
  198. unsigned char rearguard[4];
  199. } RPC_MEMORY_BLOCK;
  200. //
  201. // Compile-time test to ensure that RPC_MEMORY_BLOCK.rearguard is aligned on
  202. // natural boundary.
  203. //
  204. #if defined(_WIN64)
  205. C_ASSERT( (FIELD_OFFSET( RPC_MEMORY_BLOCK, rearguard ) % 16) == 0 );
  206. #else
  207. C_ASSERT( (FIELD_OFFSET( RPC_MEMORY_BLOCK, rearguard ) % 8) == 0 );
  208. #endif
  209. RPC_MEMORY_BLOCK * AllocatedBlocks = 0;
  210. unsigned long BlockCount = 0;
  211. int
  212. CheckMemoryBlock (
  213. RPC_MEMORY_BLOCK * block
  214. )
  215. {
  216. if ( block->frontguard[0] != RPC_GUARD
  217. || block->frontguard[1] != RPC_GUARD
  218. || block->frontguard[2] != RPC_GUARD
  219. || block->frontguard[3] != RPC_GUARD )
  220. {
  221. PrintToDebugger("RPC : BAD BLOCK (front) @ %p\n", block);
  222. ASSERT(0);
  223. return(1);
  224. }
  225. if ( block->rearguard[block->size] != RPC_GUARD
  226. || block->rearguard[block->size+1] != RPC_GUARD
  227. || block->rearguard[block->size+2] != RPC_GUARD
  228. || block->rearguard[block->size+3] != RPC_GUARD )
  229. {
  230. PrintToDebugger("RPC : BAD BLOCK (rear) @ %p (%p)\n",block, &block->rearguard[block->size]);
  231. ASSERT(0);
  232. return(1);
  233. }
  234. ASSERT(block->free == 0);
  235. if ( block->next != 0)
  236. {
  237. ASSERT(block->next->previous == block);
  238. }
  239. if ( block->previous != 0)
  240. {
  241. ASSERT(block->previous->next == block);
  242. }
  243. return(0);
  244. }
  245. int
  246. RpcValidateHeapList(
  247. void
  248. )
  249. // Called with RpcHeapLock held.
  250. {
  251. RPC_MEMORY_BLOCK * block;
  252. unsigned Blocks = 0;
  253. // Under stress this check causes performance to drop too much.
  254. // Compile with -DNO_HEAP_SLOWDOWN or ed the flag in memory
  255. // to speed things up.
  256. if (fMemoryCheck == 0)
  257. {
  258. return(0);
  259. }
  260. block = AllocatedBlocks;
  261. while (block != 0)
  262. {
  263. if (CheckMemoryBlock(block))
  264. {
  265. return(1);
  266. }
  267. block = block->next;
  268. Blocks++;
  269. }
  270. ASSERT(Blocks == BlockCount);
  271. return(0);
  272. }
  273. int
  274. RpcpCheckHeap (
  275. void
  276. )
  277. // Returns 0 if the heap appears to be okay.
  278. {
  279. if (fMemoryCheck == 0)
  280. {
  281. return(0);
  282. }
  283. EnterCriticalSection(&RpcHeapLock);
  284. int ret = RpcValidateHeapList();
  285. LeaveCriticalSection(&RpcHeapLock);
  286. return(ret);
  287. }
  288. void * __cdecl
  289. operator new(
  290. size_t size
  291. )
  292. {
  293. RPC_MEMORY_BLOCK * block;
  294. EnterCriticalSection(&RpcHeapLock);
  295. ASSERT( ("You allocated a negative amount",
  296. size < (size + sizeof(RPC_MEMORY_BLOCK))) );
  297. RpcValidateHeapList();
  298. if (DebugFlags & RPC_FAIL_ALLOCATIONS)
  299. {
  300. if ((GetTickCount() % 13) == 0)
  301. {
  302. LeaveCriticalSection(&RpcHeapLock);
  303. PrintToDebugger("RPC: Purposely failed an allocation\n") ;
  304. return 0;
  305. }
  306. }
  307. block = (RPC_MEMORY_BLOCK *)AllocWrapper(size + sizeof(RPC_MEMORY_BLOCK));
  308. if ( block == 0 )
  309. {
  310. LeaveCriticalSection(&RpcHeapLock);
  311. return(0);
  312. }
  313. block->size = size;
  314. block->tid = GetCurrentThreadId();
  315. block->free = 0;
  316. if (AllocatedBlocks != 0)
  317. AllocatedBlocks->previous = block;
  318. block->next = AllocatedBlocks;
  319. block->previous = 0;
  320. AllocatedBlocks = block;
  321. BlockCount++;
  322. block->frontguard[0] = RPC_GUARD;
  323. block->frontguard[1] = RPC_GUARD;
  324. block->frontguard[2] = RPC_GUARD;
  325. block->frontguard[3] = RPC_GUARD;
  326. #if i386
  327. ULONG ignore;
  328. RtlCaptureStackBackTrace(
  329. 2,
  330. 4,
  331. (void **) &block->AllocStackTrace,
  332. &ignore);
  333. #endif
  334. block->rearguard[size] = RPC_GUARD;
  335. block->rearguard[size+1] = RPC_GUARD;
  336. block->rearguard[size+2] = RPC_GUARD;
  337. block->rearguard[size+3] = RPC_GUARD;
  338. LeaveCriticalSection(&RpcHeapLock);
  339. return(&(block->rearguard[0]));
  340. }
  341. void __cdecl
  342. operator delete (
  343. IN void * obj
  344. )
  345. {
  346. RPC_MEMORY_BLOCK * block;
  347. if (obj == 0)
  348. return;
  349. EnterCriticalSection(&RpcHeapLock);
  350. block = (RPC_MEMORY_BLOCK *) (((unsigned char *) obj)
  351. - FIELD_OFFSET(RPC_MEMORY_BLOCK, rearguard));
  352. // Validate block being freed.
  353. CheckMemoryBlock(block);
  354. if (block->next != 0)
  355. {
  356. CheckMemoryBlock(block->next);
  357. }
  358. if (block->previous != 0)
  359. {
  360. CheckMemoryBlock(block->previous);
  361. }
  362. // Remove the block from the list
  363. if (block == AllocatedBlocks)
  364. AllocatedBlocks = block->next;
  365. if (block->next != 0)
  366. block->next->previous = block->previous;
  367. if (block->previous != 0)
  368. block->previous->next = block->next;
  369. // Mark this block as free
  370. block->free = 0xF0F0F0F0;
  371. // Validate other RPC allocations.
  372. BlockCount-- ;
  373. RpcValidateHeapList();
  374. LeaveCriticalSection(&RpcHeapLock);
  375. FreeWrapper(block);
  376. }
  377. #endif // DEBUGRPC