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.

492 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. delete gBufferCache;
  175. return(RPC_S_OUT_OF_MEMORY);
  176. }
  177. fBufferCacheInitialized = TRUE;
  178. }
  179. return(RPC_S_OK);
  180. }
  181. #define RPC_GUARD 0xA1
  182. typedef struct _RPC_MEMORY_BLOCK
  183. {
  184. // First,forward and backward links to other RPC heap allocations.
  185. // These are first allow easy debugging with the dl command
  186. struct _RPC_MEMORY_BLOCK *next;
  187. struct _RPC_MEMORY_BLOCK *previous;
  188. // Specifies the size of the block of memory in bytes.
  189. unsigned long size;
  190. // Thread id of allocator
  191. unsigned long tid;
  192. void * AllocStackTrace[4];
  193. // (Pad to make header 0 mod 8) 0 when allocated, 0xF0F0F0F0 when freed.
  194. unsigned long free;
  195. // Reserve an extra 4 bytes as the front guard of each block.
  196. unsigned char frontguard[4];
  197. // Data will appear here. Note that the header must be 0 mod 8.
  198. // Reserve an extra 4 bytes as the rear guard of each block.
  199. unsigned char rearguard[4];
  200. } RPC_MEMORY_BLOCK;
  201. //
  202. // Compile-time test to ensure that RPC_MEMORY_BLOCK.rearguard is aligned on
  203. // natural boundary.
  204. //
  205. #if defined(_WIN64)
  206. C_ASSERT( (FIELD_OFFSET( RPC_MEMORY_BLOCK, rearguard ) % 16) == 0 );
  207. #else
  208. C_ASSERT( (FIELD_OFFSET( RPC_MEMORY_BLOCK, rearguard ) % 8) == 0 );
  209. #endif
  210. RPC_MEMORY_BLOCK * AllocatedBlocks = 0;
  211. unsigned long BlockCount = 0;
  212. int
  213. CheckMemoryBlock (
  214. RPC_MEMORY_BLOCK * block
  215. )
  216. {
  217. if ( block->frontguard[0] != RPC_GUARD
  218. || block->frontguard[1] != RPC_GUARD
  219. || block->frontguard[2] != RPC_GUARD
  220. || block->frontguard[3] != RPC_GUARD )
  221. {
  222. PrintToDebugger("RPC : BAD BLOCK (front) @ %p\n", block);
  223. ASSERT(0);
  224. return(1);
  225. }
  226. if ( block->rearguard[block->size] != RPC_GUARD
  227. || block->rearguard[block->size+1] != RPC_GUARD
  228. || block->rearguard[block->size+2] != RPC_GUARD
  229. || block->rearguard[block->size+3] != RPC_GUARD )
  230. {
  231. PrintToDebugger("RPC : BAD BLOCK (rear) @ %p (%p)\n",block, &block->rearguard[block->size]);
  232. ASSERT(0);
  233. return(1);
  234. }
  235. ASSERT(block->free == 0);
  236. if ( block->next != 0)
  237. {
  238. ASSERT(block->next->previous == block);
  239. }
  240. if ( block->previous != 0)
  241. {
  242. ASSERT(block->previous->next == block);
  243. }
  244. return(0);
  245. }
  246. int
  247. RpcValidateHeapList(
  248. void
  249. )
  250. // Called with RpcHeapLock held.
  251. {
  252. RPC_MEMORY_BLOCK * block;
  253. unsigned Blocks = 0;
  254. // Under stress this check causes performance to drop too much.
  255. // Compile with -DNO_HEAP_SLOWDOWN or ed the flag in memory
  256. // to speed things up.
  257. if (fMemoryCheck == 0)
  258. {
  259. return(0);
  260. }
  261. block = AllocatedBlocks;
  262. while (block != 0)
  263. {
  264. if (CheckMemoryBlock(block))
  265. {
  266. return(1);
  267. }
  268. block = block->next;
  269. Blocks++;
  270. }
  271. ASSERT(Blocks == BlockCount);
  272. return(0);
  273. }
  274. int
  275. RpcpCheckHeap (
  276. void
  277. )
  278. // Returns 0 if the heap appears to be okay.
  279. {
  280. if (fMemoryCheck == 0)
  281. {
  282. return(0);
  283. }
  284. EnterCriticalSection(&RpcHeapLock);
  285. int ret = RpcValidateHeapList();
  286. LeaveCriticalSection(&RpcHeapLock);
  287. return(ret);
  288. }
  289. void * __cdecl
  290. operator new(
  291. size_t size
  292. )
  293. {
  294. RPC_MEMORY_BLOCK * block;
  295. EnterCriticalSection(&RpcHeapLock);
  296. ASSERT( ("You allocated a negative amount",
  297. size < (size + sizeof(RPC_MEMORY_BLOCK))) );
  298. RpcValidateHeapList();
  299. if (DebugFlags & RPC_FAIL_ALLOCATIONS)
  300. {
  301. if ((GetTickCount() % 13) == 0)
  302. {
  303. LeaveCriticalSection(&RpcHeapLock);
  304. PrintToDebugger("RPC: Purposely failed an allocation\n") ;
  305. return 0;
  306. }
  307. }
  308. block = (RPC_MEMORY_BLOCK *)AllocWrapper(size + sizeof(RPC_MEMORY_BLOCK));
  309. if ( block == 0 )
  310. {
  311. LeaveCriticalSection(&RpcHeapLock);
  312. return(0);
  313. }
  314. block->size = size;
  315. block->tid = GetCurrentThreadId();
  316. block->free = 0;
  317. if (AllocatedBlocks != 0)
  318. AllocatedBlocks->previous = block;
  319. block->next = AllocatedBlocks;
  320. block->previous = 0;
  321. AllocatedBlocks = block;
  322. BlockCount++;
  323. block->frontguard[0] = RPC_GUARD;
  324. block->frontguard[1] = RPC_GUARD;
  325. block->frontguard[2] = RPC_GUARD;
  326. block->frontguard[3] = RPC_GUARD;
  327. #if i386
  328. ULONG ignore;
  329. RtlCaptureStackBackTrace(
  330. 2,
  331. 4,
  332. (void **) &block->AllocStackTrace,
  333. &ignore);
  334. #endif
  335. block->rearguard[size] = RPC_GUARD;
  336. block->rearguard[size+1] = RPC_GUARD;
  337. block->rearguard[size+2] = RPC_GUARD;
  338. block->rearguard[size+3] = RPC_GUARD;
  339. LeaveCriticalSection(&RpcHeapLock);
  340. return(&(block->rearguard[0]));
  341. }
  342. void __cdecl
  343. operator delete (
  344. IN void * obj
  345. )
  346. {
  347. RPC_MEMORY_BLOCK * block;
  348. if (obj == 0)
  349. return;
  350. EnterCriticalSection(&RpcHeapLock);
  351. block = (RPC_MEMORY_BLOCK *) (((unsigned char *) obj)
  352. - FIELD_OFFSET(RPC_MEMORY_BLOCK, rearguard));
  353. // Validate block being freed.
  354. CheckMemoryBlock(block);
  355. if (block->next != 0)
  356. {
  357. CheckMemoryBlock(block->next);
  358. }
  359. if (block->previous != 0)
  360. {
  361. CheckMemoryBlock(block->previous);
  362. }
  363. // Remove the block from the list
  364. if (block == AllocatedBlocks)
  365. AllocatedBlocks = block->next;
  366. if (block->next != 0)
  367. block->next->previous = block->previous;
  368. if (block->previous != 0)
  369. block->previous->next = block->next;
  370. // Mark this block as free
  371. block->free = 0xF0F0F0F0;
  372. // Validate other RPC allocations.
  373. BlockCount-- ;
  374. RpcValidateHeapList();
  375. LeaveCriticalSection(&RpcHeapLock);
  376. FreeWrapper(block);
  377. }
  378. #endif // DEBUGRPC