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.

661 lines
20 KiB

  1. /***
  2. *heapinit.c - Initialze the heap
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * 06-28-89 JCR Module created.
  10. * 06-30-89 JCR Added _heap_grow_emptylist
  11. * 11-13-89 GJF Fixed copyright
  12. * 11-15-89 JCR Moved _heap_abort routine to another module
  13. * 12-15-89 GJF Removed DEBUG286 stuff, did some tuning, changed header
  14. * file name to heap.h and made functions explicitly
  15. * _cdecl.
  16. * 12-19-89 GJF Removed plastdesc field from _heap_desc_ struct
  17. * 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
  18. * <cruntime.h> and removed #include <register.h>.
  19. * 07-24-90 SBM Removed '32' from API names
  20. * 10-03-90 GJF New-style function declarators.
  21. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  22. * 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
  23. * 02-01-91 SRW Changed for new VirtualAlloc interface (_WIN32_)
  24. * 03-05-91 GJF Added definition of _heap_resetsize (conditioned on
  25. * _OLDROVER_ not being #define-d).
  26. * 04-04-91 GJF Reduce _heap_regionsize to 1/2 a meg for Dosx32
  27. * (_WIN32_).
  28. * 04-05-91 GJF Temporary hack for Win32/DOS folks - special version
  29. * of _heap_init which calls HeapCreate. The change
  30. * conditioned on _WIN32DOS_.
  31. * 04-09-91 PNT Added _MAC_ conditional
  32. * 02-23-93 SKS Remove DOSX32 support under WIN32 ifdef
  33. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  34. * 04-26-93 SKS Add variable _heap_maxregsize (was _HEAP_MAXREGIONSIZE)
  35. * Initialize _heap_[max,]reg[,ion]size to Large defaults
  36. * heapinit() tests _osver to detect Small memory case
  37. * 05-06-93 SKS Add _heap_term() to return heap memory to the o.s.
  38. * 01-17-94 SKS Check _osver AND _winmajor to detect Small memory case.
  39. * 03-02-94 GJF Changed _heap_grow_emptylist so that it returns a
  40. * failure code rather than calling _heap_abort.
  41. * 03-30-94 GJF Made definitions/declarations of:
  42. * _heap_desc
  43. * _heap_descpages,
  44. * _heap_growsize (aka, _amblksiz),
  45. * _heap_maxregsize
  46. * _heap_regionsize
  47. * _heap_regions
  48. * conditional on ndef DLL_FOR_WIN32S.
  49. * 02-08-95 GJF Removed obsolete _OLDROVER_ support.
  50. * 02-14-95 GJF Appended Mac version of source file.
  51. * 04-30-95 GJF Spliced on winheap version.
  52. * 03-06-96 GJF Added initialization and termination code for the
  53. * small-block heap.
  54. * 04-22-97 GJF Changed _heap_init to return 1 for success, 0 for
  55. * failure.
  56. * 05-30-96 GJF Minor changes for latest version of small-block heap.
  57. * 05-22-97 RDK New small-block heap scheme implemented.
  58. * 07-23-97 GJF Changed _heap_init() slightly to accomodate optional
  59. * heap running directly on Win32 API (essentially the
  60. * scheme we used in VC++ 4.0 and 4.1).
  61. * 09-26-97 BWT Fix POSIX
  62. * 09-28-98 GJF Don't initialize the small-block heap on NT 5.
  63. * 11-18-98 GJF Merged in VC++ 5.0 small-block heap and a selection
  64. * scheme from James "Triple-Expresso" MacCalman and
  65. * Chairman Dan Spalding.
  66. * 05-01-99 PML Disable small-block heap for Win64.
  67. * 05-13-99 PML Remove Win32s
  68. * 05-17-99 PML Remove all Macintosh support.
  69. * 06-17-99 GJF Removed old small-block heap from static libs.
  70. * 09-28-99 PML Processing heap-select env var must not do anything
  71. * that uses the heap (vs7#44259). Also, check the env
  72. * var before checking for NT5.0 or better.
  73. * 03-28-01 PML Protect against GetModuleFileName overflow (vs7#231284)
  74. * 06-25-01 BWT Alloc heap select strings off the process heap instead of
  75. * the stack (ntbug: 423988)
  76. * 11-03-01 PML Add _get_heap_handle
  77. *
  78. *******************************************************************************/
  79. #ifdef WINHEAP
  80. #include <cruntime.h>
  81. #include <malloc.h>
  82. #include <stdlib.h>
  83. #include <winheap.h>
  84. HANDLE _crtheap;
  85. #if !defined(_NTSDK)
  86. /*
  87. * Dummy definition of _amblksiz. Included primarily so the dll will build
  88. * without having to change crtlib.c (there is an access function for _amblksiz
  89. * defined in crtlib.c).
  90. */
  91. unsigned int _amblksiz = BYTES_PER_PARA;
  92. #endif
  93. #ifndef _WIN64
  94. int __active_heap;
  95. #ifdef CRTDLL
  96. void __cdecl _GetLinkerVersion(LinkerVersion * plv)
  97. {
  98. PIMAGE_DOS_HEADER pidh;
  99. PIMAGE_NT_HEADERS pinh;
  100. plv->dw = 0;
  101. pidh = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL);
  102. if ( pidh->e_magic != IMAGE_DOS_SIGNATURE || pidh->e_lfanew == 0)
  103. return;
  104. pinh = (PIMAGE_NT_HEADERS)(((PBYTE)pidh) + pidh->e_lfanew);
  105. plv->bverMajor = pinh->OptionalHeader.MajorLinkerVersion;
  106. plv->bverMinor = pinh->OptionalHeader.MinorLinkerVersion;
  107. }
  108. #endif /* CRTDLL */
  109. /***
  110. *__heap_select() - Choose from the V6, V5 or system heaps
  111. *
  112. *Purpose:
  113. * Check OS, environment and build bits to determine appropriate
  114. * small-block heap for the app.
  115. *
  116. *Entry:
  117. * <void>
  118. *Exit:
  119. * Returns __V6_HEAP, __V5_HEAP or __SYSTEM_HEAP
  120. *
  121. *Exceptions:
  122. * none
  123. *
  124. *******************************************************************************/
  125. int __cdecl __heap_select(void)
  126. {
  127. char *env_heap_type = NULL;
  128. #ifdef CRTDLL
  129. DWORD HeapStringSize;
  130. char *cp, *env_heap_select_string = NULL;
  131. int heap_choice;
  132. LinkerVersion lv;
  133. #endif /* CRTDLL */
  134. #ifdef CRTDLL
  135. // First, check the environment variable override
  136. if (HeapStringSize = GetEnvironmentVariableA(__HEAP_ENV_STRING, env_heap_select_string, 0))
  137. {
  138. env_heap_select_string = HeapAlloc(GetProcessHeap(), 0, HeapStringSize);
  139. if (env_heap_select_string)
  140. {
  141. if (GetEnvironmentVariableA(__HEAP_ENV_STRING, env_heap_select_string, HeapStringSize))
  142. {
  143. for (cp = env_heap_select_string; *cp; ++cp)
  144. if ('a' <= *cp && *cp <= 'z')
  145. *cp += 'A' - 'a';
  146. if (!strncmp(__GLOBAL_HEAP_SELECTOR,env_heap_select_string,sizeof(__GLOBAL_HEAP_SELECTOR)-1))
  147. env_heap_type = env_heap_select_string;
  148. else
  149. {
  150. char *env_app_name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH+1);
  151. if (env_app_name) {
  152. GetModuleFileName(NULL,env_app_name,sizeof(env_app_name)-1);
  153. for (cp = env_app_name; *cp; ++cp)
  154. if ('a' <= *cp && *cp <= 'z')
  155. *cp += 'A' - 'a';
  156. env_heap_type = strstr(env_heap_select_string,env_app_name);
  157. HeapFree(GetProcessHeap(), 0, env_app_name);
  158. }
  159. }
  160. if (env_heap_type)
  161. {
  162. if (env_heap_type = strchr(env_heap_type,','))
  163. {
  164. // Convert ASCII heap code to integer inline, since
  165. // strtol would try to use the heap (for locale info).
  166. cp = ++env_heap_type;
  167. while (*cp == ' ')
  168. ++cp;
  169. heap_choice = 0;
  170. while (*cp >= '0' && *cp <= '9')
  171. heap_choice = heap_choice * 10 + *cp++ - '0';
  172. if ( (heap_choice == __V5_HEAP) ||
  173. (heap_choice == __V6_HEAP) ||
  174. (heap_choice == __SYSTEM_HEAP) )
  175. {
  176. HeapFree(GetProcessHeap(), 0, env_heap_select_string);
  177. return heap_choice;
  178. }
  179. }
  180. }
  181. }
  182. HeapFree(GetProcessHeap(), 0, env_heap_select_string);
  183. }
  184. }
  185. #endif /* CRTDLL */
  186. // Second, check the OS for NT >= 5.0
  187. if ( (_osplatform == VER_PLATFORM_WIN32_NT) && (_winmajor >= 5) )
  188. return __SYSTEM_HEAP;
  189. #ifdef CRTDLL
  190. // Third, check the build bits in the app; apps built with tools >= VC++ 6.0
  191. // will get the V6 heap, apps built with older tools will get the V5 heap
  192. _GetLinkerVersion(&lv);
  193. if (lv.bverMajor >= 6)
  194. return __V6_HEAP;
  195. else
  196. return __V5_HEAP;
  197. #else /* ndef CRTDLL */
  198. return __V6_HEAP;
  199. #endif /* CRTDLL */
  200. }
  201. #endif /* ndef _WIN64 */
  202. /***
  203. *_heap_init() - Initialize the heap
  204. *
  205. *Purpose:
  206. * Setup the initial C library heap.
  207. *
  208. * NOTES:
  209. * (1) This routine should only be called once!
  210. * (2) This routine must be called before any other heap requests.
  211. *
  212. *Entry:
  213. * <void>
  214. *Exit:
  215. * Returns 1 if successful, 0 otherwise.
  216. *
  217. *Exceptions:
  218. * If heap cannot be initialized, the program will be terminated
  219. * with a fatal runtime error.
  220. *
  221. *******************************************************************************/
  222. int __cdecl _heap_init (
  223. int mtflag
  224. )
  225. {
  226. #ifdef _POSIX_
  227. _crtheap = GetProcessHeap();
  228. #else
  229. // Initialize the "big-block" heap first.
  230. if ( (_crtheap = HeapCreate( mtflag ? 0 : HEAP_NO_SERIALIZE,
  231. BYTES_PER_PAGE, 0 )) == NULL )
  232. return 0;
  233. #ifndef _WIN64
  234. // Pick a heap, any heap
  235. __active_heap = __heap_select();
  236. if ( __active_heap == __V6_HEAP )
  237. {
  238. // Initialize the small-block heap
  239. if (__sbh_heap_init(MAX_ALLOC_DATA_SIZE) == 0)
  240. {
  241. HeapDestroy(_crtheap);
  242. return 0;
  243. }
  244. }
  245. #ifdef CRTDLL
  246. else if ( __active_heap == __V5_HEAP )
  247. {
  248. if ( __old_sbh_new_region() == NULL )
  249. {
  250. HeapDestroy( _crtheap );
  251. return 0;
  252. }
  253. }
  254. #endif /* CRTDLL */
  255. #endif /* _ndef _WIN64 */
  256. #endif /* _POSIX_ */
  257. return 1;
  258. }
  259. /***
  260. *_heap_term() - return the heap to the OS
  261. *
  262. *Purpose:
  263. *
  264. * NOTES:
  265. * (1) This routine should only be called once!
  266. * (2) This routine must be called AFTER any other heap requests.
  267. *
  268. *Entry:
  269. * <void>
  270. *Exit:
  271. * <void>
  272. *
  273. *Exceptions:
  274. *
  275. *******************************************************************************/
  276. void __cdecl _heap_term (void)
  277. {
  278. #ifndef _POSIX_
  279. #ifndef _WIN64
  280. // if it has been initialized, destroy the small-block heap
  281. if ( __active_heap == __V6_HEAP )
  282. {
  283. PHEADER pHeader = __sbh_pHeaderList;
  284. int cntHeader;
  285. // scan through all the headers
  286. for (cntHeader = 0; cntHeader < __sbh_cntHeaderList; cntHeader++)
  287. {
  288. // decommit and release the address space for the region
  289. VirtualFree(pHeader->pHeapData, BYTES_PER_REGION, MEM_DECOMMIT);
  290. VirtualFree(pHeader->pHeapData, 0, MEM_RELEASE);
  291. // free the region data structure
  292. HeapFree(_crtheap, 0, pHeader->pRegion);
  293. pHeader++;
  294. }
  295. // free the header list
  296. HeapFree(_crtheap, 0, __sbh_pHeaderList);
  297. }
  298. #ifdef CRTDLL
  299. else if ( __active_heap == __V5_HEAP )
  300. {
  301. __old_sbh_region_t *preg = &__old_small_block_heap;
  302. // Release the regions of the small-block heap
  303. do
  304. {
  305. if ( preg->p_pages_begin != NULL )
  306. VirtualFree( preg->p_pages_begin, 0, MEM_RELEASE );
  307. }
  308. while ( (preg = preg->p_next_region) != &__old_small_block_heap );
  309. }
  310. #endif /* CRTDLL */
  311. #endif /* ndef _WIN64 */
  312. // destroy the large-block heap
  313. HeapDestroy(_crtheap);
  314. #endif /* _POSIX_ */
  315. }
  316. /***
  317. *_get_heap_handle() - Get the HANDLE to the Win32 system heap used by the CRT
  318. *
  319. *Purpose:
  320. * Retrieve the HANDLE to the Win32 system heap used by the CRT.
  321. *
  322. *Entry:
  323. * <void>
  324. *Exit:
  325. * Returns the CRT heap HANDLE as an intptr_t
  326. *
  327. *Exceptions:
  328. *
  329. *******************************************************************************/
  330. intptr_t __cdecl _get_heap_handle(void)
  331. {
  332. return (intptr_t)_crtheap;
  333. }
  334. #else /* ndef WINHEAP */
  335. #include <cruntime.h>
  336. #include <oscalls.h>
  337. #include <dos.h>
  338. #include <heap.h>
  339. #include <stddef.h>
  340. #include <stdio.h>
  341. #include <stdlib.h>
  342. /*
  343. * Heap descriptor
  344. */
  345. struct _heap_desc_ _heap_desc = {
  346. &_heap_desc.sentinel, /* pfirstdesc */
  347. &_heap_desc.sentinel, /* proverdesc */
  348. NULL, /* emptylist */
  349. NULL, /* sentinel.pnextdesc */
  350. NULL /* sentinel.pblock */
  351. };
  352. /*
  353. * Array of region structures
  354. * [Note: We count on the fact that this is always initialized to zero
  355. * by the compiler.]
  356. */
  357. struct _heap_region_ _heap_regions[_HEAP_REGIONMAX];
  358. void ** _heap_descpages; /* linked list of pages used for descriptors */
  359. /*
  360. * Control parameter locations
  361. */
  362. unsigned int _heap_resetsize = 0xffffffff;
  363. /* NOTE: Currenlty, _heap_growsize is a #define to _amblksiz */
  364. unsigned int _heap_growsize = _HEAP_GROWSIZE; /* region inc size */
  365. unsigned int _heap_regionsize = _HEAP_REGIONSIZE_L; /* region size */
  366. unsigned int _heap_maxregsize = _HEAP_MAXREGSIZE_L; /* max region size */
  367. /***
  368. *_heap_init() - Initialize the heap
  369. *
  370. *Purpose:
  371. * Setup the initial C library heap. All necessary memory and
  372. * data bases are init'd appropriately so future requests work
  373. * correctly.
  374. *
  375. * NOTES:
  376. * (1) This routine should only be called once!
  377. * (2) This routine must be called before any other heap requests.
  378. *
  379. *
  380. *Entry:
  381. * <void>
  382. *Exit:
  383. * <void>
  384. *
  385. *Exceptions:
  386. * If heap cannot be initialized, the program will be terminated
  387. * with a fatal runtime error.
  388. *
  389. *******************************************************************************/
  390. void __cdecl _heap_init (
  391. void
  392. )
  393. {
  394. /*
  395. * Test for Win32S or Phar Lap TNT environment
  396. * which cannot allocate uncommitted memory
  397. * without actually allocating physical memory
  398. *
  399. * High bit of _osver is set for both of those environments
  400. * -AND- the Windows version will be less than 4.0.
  401. */
  402. if ( ( _osver & 0x8000 ) && ( _winmajor < 4 ) )
  403. {
  404. _heap_regionsize = _HEAP_REGIONSIZE_S;
  405. _heap_maxregsize = _HEAP_MAXREGSIZE_S;
  406. }
  407. }
  408. /***
  409. *_heap_term() - Clean-up the heap
  410. *
  411. *Purpose:
  412. * This routine will decommit and release ALL of the CRT heap.
  413. * All memory malloc-ed by the CRT will then be invalid.
  414. *
  415. * NOTES:
  416. * (1) This routine should only be called once!
  417. * (2) This routine must be called AFTER any other heap requests.
  418. *
  419. *Entry:
  420. * <void>
  421. *Exit:
  422. * <void>
  423. *
  424. *Exceptions:
  425. *
  426. *******************************************************************************/
  427. void __cdecl _heap_term (
  428. void
  429. )
  430. {
  431. int index;
  432. void **pageptr;
  433. /*
  434. * Loop through the region descriptor table, decommitting
  435. * and releasing (freeing up) each region that is in use.
  436. */
  437. for ( index=0 ; index < _HEAP_REGIONMAX ; index++ ) {
  438. void * regbase ;
  439. if ( (regbase = _heap_regions[index]._regbase)
  440. && VirtualFree(regbase, _heap_regions[index]._currsize, MEM_DECOMMIT)
  441. && VirtualFree(regbase, 0, MEM_RELEASE) )
  442. regbase = _heap_regions[index]._regbase = NULL ;
  443. }
  444. /*
  445. * Now we need to decommit and release the pages used for descriptors
  446. * _heap_descpages points to the head of a singly-linked list of the pages.
  447. */
  448. pageptr = _heap_descpages;
  449. while ( pageptr ) {
  450. void **nextpage;
  451. nextpage = *pageptr;
  452. if(!VirtualFree(pageptr, 0, MEM_RELEASE))
  453. break; /* if the linked list is corrupted, give up */
  454. pageptr = nextpage;
  455. }
  456. }
  457. /***
  458. * _heap_grow_emptylist() - Grow the empty heap descriptor list
  459. *
  460. *Purpose:
  461. * (1) Get memory from OS
  462. * (2) Form it into a linked list of empty heap descriptors
  463. * (3) Attach it to the master empty list
  464. *
  465. * NOTE: This routine assumes that the emptylist is NULL
  466. * when called (i.e., there are no available empty heap descriptors).
  467. *
  468. *Entry:
  469. * (void)
  470. *
  471. *Exit:
  472. * 1, if the empty heap descriptor list was grown
  473. * 0, if the empty heap descriptor list could not be grown.
  474. *
  475. *Exceptions:
  476. *
  477. *******************************************************************************/
  478. static int __cdecl _heap_grow_emptylist (
  479. void
  480. )
  481. {
  482. REG1 _PBLKDESC first;
  483. REG2 _PBLKDESC next;
  484. _PBLKDESC last;
  485. /*
  486. * Get memory for the new empty heap descriptors
  487. *
  488. * Note that last is used to hold the returned pointer because
  489. * first (and next) are register class.
  490. */
  491. if ( !(last = VirtualAlloc(NULL,
  492. _HEAP_EMPTYLIST_SIZE,
  493. MEM_COMMIT,
  494. PAGE_READWRITE)) )
  495. return 0;
  496. /*
  497. * Add this descriptor block to the front of the list
  498. *
  499. * Advance "last" to skip over the
  500. */
  501. *(void **)last = _heap_descpages;
  502. _heap_descpages = (void **)(last++);
  503. /*
  504. * Init the empty heap descriptor list.
  505. */
  506. _heap_desc.emptylist = first = last;
  507. /*
  508. * Carve the memory into an empty list
  509. */
  510. last = (_PBLKDESC) ((char *) first + _HEAP_EMPTYLIST_SIZE - 2 * sizeof(_BLKDESC));
  511. next = (_PBLKDESC) ((char *) first + sizeof(_BLKDESC));
  512. while ( first < last ) {
  513. /* Init this descriptor */
  514. #ifdef DEBUG
  515. first->pblock = NULL;
  516. #endif
  517. first->pnextdesc = next;
  518. /* onto the next block */
  519. first = next++;
  520. }
  521. /*
  522. * Take care of the last descriptor (end of the empty list)
  523. */
  524. last->pnextdesc = NULL;
  525. #ifdef DEBUG
  526. last->pblock = NULL;
  527. #endif
  528. return 1;
  529. }
  530. /***
  531. *__getempty() - get an empty heap descriptor
  532. *
  533. *Purpose:
  534. * Get a descriptor from the list of empty heap descriptors. If the list
  535. * is empty, call _heap_grow_emptylist.
  536. *
  537. *Entry:
  538. * no arguments
  539. *
  540. *Exit:
  541. * If successful, a pointer to the descriptor is returned.
  542. * Otherwise, NULL is returned.
  543. *
  544. *Exceptions:
  545. *
  546. *******************************************************************************/
  547. _PBLKDESC __cdecl __getempty(
  548. void
  549. )
  550. {
  551. _PBLKDESC pdesc;
  552. if ( (_heap_desc.emptylist == NULL) && (_heap_grow_emptylist()
  553. == 0) )
  554. return NULL;
  555. pdesc = _heap_desc.emptylist;
  556. _heap_desc.emptylist = pdesc->pnextdesc;
  557. return pdesc;
  558. }
  559. #endif /* WINHEAP */