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.

428 lines
14 KiB

  1. /***
  2. *malloc.c - Get a block of memory from the heap
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Defines the malloc() function.
  8. *
  9. *Revision History:
  10. * 06-29-89 GJF Module created (no rest for the wicked).
  11. * 07-07-89 GJF Several bug fixes
  12. * 07-21-89 GJF Added code to maintain proverdesc such that proverdesc
  13. * either points to the descriptor for the first free
  14. * block in the heap or, if there are no free blocks, is
  15. * the same as plastdesc.
  16. * 11-07-89 GJF Substantially revised to cope with 'tiling'.
  17. * 11-09-89 GJF Embarrassing bug (didn't bother to assign pdesc)
  18. * 11-10-89 GJF Added MTHREAD support.
  19. * 11-17-89 GJF Oops, must call _free_lk() instead of free()!
  20. * 12-18-89 GJF Changed name of header file to heap.h, also added
  21. * explicit _cdecl to function definitions.
  22. * 12-19-89 GJF Got rid of plastdesc from _heap_split_block() and
  23. * _ heap_advance_rover().
  24. * 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
  25. * <cruntime.h> and removed #include <register.h>.
  26. * 07-25-90 SBM Replaced <stdio.h> by <stddef.h>, replaced
  27. * <assertm.h> by <assert.h>
  28. * 09-28-90 GJF New-style function declarators.
  29. * 02-26-91 SRW Optimize heap rover for _WIN32_.
  30. * 03-07-91 FAR Fix bug in heap rover
  31. * 03-11-91 FAR REALLY Fix bug in heap rover
  32. * 03-14-91 GJF Changed strategy for rover - old version available
  33. * by #define-ing _OLDROVER_.
  34. * 04-05-91 GJF Temporary hack for Win32/DOS folks - special version
  35. * of malloc that just calls HeapAlloc. Change conditioned
  36. * on _WIN32DOS_.
  37. * 05-28-91 GJF Removed M_I386 conditionals and put in _CRUISER_
  38. * conditionals so the 'tiling' version is built only for
  39. * Cruiser.
  40. * 03-03-93 SKS Add new handler support (_pnhHeap and related code)
  41. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  42. * 09-22-93 GJF Turned on range check. Also, removed old Cruiser
  43. * support.
  44. * 12-09-93 GJF Replace 4 (bytes) with _GRANULARITY.
  45. * 02-16-94 SKS Move set_new_handler support to new() in new.cxx
  46. * 03-01-94 SKS Declare _pnhHeap, pointer to the new handler, here
  47. * 03-02-94 GJF Changed logic of, and interface to, _heap_split_block
  48. * so that it may fail for lack of a free descriptor.
  49. * Also, changed malloc() so that the too-large block is
  50. * returned to the caller when _heap_split_block fails.
  51. * 03-03-94 SKS Reimplement new() handling within malloc - new scheme
  52. * allows the new() handler to be called optionally on
  53. * malloc failures. _set_new_mode(1) enables the option.
  54. * 03-04-94 SKS Rename _nhMode to _newmode, move it to its own module.
  55. * 03-02-94 GJF Changed logic of, and interface to, _heap_split_block
  56. * so that it may fail for lack of a free descriptor.
  57. * Also, changed malloc() so that the too-large block is
  58. * returned to the caller when _heap_split_block fails.
  59. * 04-01-94 GJF Made definition of _pnhHeap and declaration of
  60. * _newmode conditional on DLL_FOR_WIN32S.
  61. * 11-03-94 CFW Debug heap support.
  62. * 12-01-94 CFW Simplify debug interface.
  63. * 02-06-95 CFW assert -> _ASSERTE.
  64. * 02-07-95 GJF Deleted _OLDROVER_ code (obsolete). Also made some
  65. * temporary, conditional changes so this file can be
  66. * used in the MAC builds.
  67. * 02-09-95 GJF Restored *_base names.
  68. * 05-01-95 GJF Spliced on winheap version.
  69. * 05-24-95 CFW Official ANSI C++ new handler added.
  70. * 06-23-95 CFW ANSI new handler removed, fix block size check.
  71. * 03-01-96 GJF Added support for small-block heap. Also, the case
  72. * where size is too big now gets passed to the
  73. * new-handler.
  74. * 05-22-97 RDK New small-block heap scheme implemented.
  75. * 09-26-97 BWT Fix POSIX
  76. * 10-03-97 JWM Removed superfluous "#endif * _POSIX *"
  77. * 11-04-97 GJF Small POSIX fixes from Roger Lanser.
  78. * 12-17-97 GJF Exception-safe locking.
  79. * 05-22-98 JWM Support for KFrei's RTC work.
  80. * 07-28-98 JWM RTC update.
  81. * 09-30-98 GJF Bypass all small-block heap code when __sbh_initialized
  82. * is 0.
  83. * 11-16-98 GJF Merged in VC++ 5.0 version of small-block heap.
  84. * 12-18-98 GJF Changes for 64-bit size_t.
  85. * 05-01-99 PML Disable small-block heap for Win64.
  86. * 05-13-99 PML Remove Win32s
  87. * 05-26-99 KBF Updated RTC hook func params
  88. * 06-22-99 GJF Removed old small-block heap from static libs.
  89. * 04-28-00 BWT Fix Posix
  90. * 08-04-00 PML Don't round allocation sizes when using system
  91. * heap (VS7#131005).
  92. *
  93. *******************************************************************************/
  94. #include <cruntime.h>
  95. #include <malloc.h>
  96. #include <internal.h>
  97. #include <mtdll.h>
  98. #include <dbgint.h>
  99. #ifdef WINHEAP
  100. #include <windows.h>
  101. #include <winheap.h>
  102. #include <rtcsup.h>
  103. #else
  104. #include <heap.h>
  105. #endif
  106. #ifndef _POSIX_
  107. extern int _newmode; /* malloc new() handler mode */
  108. #endif /* _POSIX_ */
  109. /***
  110. *void *malloc(size_t size) - Get a block of memory from the heap
  111. *
  112. *Purpose:
  113. * Allocate of block of memory of at least size bytes from the heap and
  114. * return a pointer to it.
  115. *
  116. * Calls the new appropriate new handler (if installed).
  117. *
  118. *Entry:
  119. * size_t size - size of block requested
  120. *
  121. *Exit:
  122. * Success: Pointer to memory block
  123. * Failure: NULL (or some error value)
  124. *
  125. *Uses:
  126. *
  127. *Exceptions:
  128. *
  129. *******************************************************************************/
  130. void * __cdecl _malloc_base (size_t size)
  131. #ifdef _POSIX_
  132. #define _PARASIZE 0x10
  133. {
  134. size = (size + _PARASIZE - 1) & ~(_PARASIZE - 1);
  135. return HeapAlloc( _crtheap, 0, size );
  136. }
  137. #else
  138. {
  139. void *res = _nh_malloc_base(size, _newmode);
  140. RTCCALLBACK(_RTC_Allocate_hook, (res, size, 0));
  141. return res;
  142. }
  143. /***
  144. *void *_nh_malloc_base(size_t size) - Get a block of memory from the heap
  145. *
  146. *Purpose:
  147. * Allocate of block of memory of at least size bytes from the heap and
  148. * return a pointer to it.
  149. *
  150. * Calls the appropriate new handler (if installed).
  151. *
  152. * There are two distinct new handler schemes supported. The 'new' ANSI
  153. * C++ scheme overrides the 'old' scheme when it is activated. A value of
  154. * _NOPTH for the 'new' handler indicates that it is inactivated and the
  155. * 'old' handler is then called.
  156. *
  157. *Entry:
  158. * size_t size - size of block requested
  159. *
  160. *Exit:
  161. * Success: Pointer to memory block
  162. * Failure: NULL (or some error value)
  163. *
  164. *Uses:
  165. *
  166. *Exceptions:
  167. *
  168. *******************************************************************************/
  169. void * __cdecl _nh_malloc_base (size_t size, int nhFlag)
  170. {
  171. void * pvReturn;
  172. // validate size
  173. if (size > _HEAP_MAXREQ)
  174. return NULL;
  175. #ifndef WINHEAP
  176. /* round requested size */
  177. size = _ROUND2(size, _GRANULARITY);
  178. #endif /* WINHEAP */
  179. for (;;) {
  180. // allocate memory block
  181. if (size <= _HEAP_MAXREQ)
  182. pvReturn = _heap_alloc_base(size);
  183. else
  184. pvReturn = NULL;
  185. // if successful allocation, return pointer to memory
  186. // if new handling turned off altogether, return NULL
  187. if (pvReturn || nhFlag == 0)
  188. return pvReturn;
  189. // call installed new handler
  190. if (!_callnewh(size))
  191. return NULL;
  192. // new handler was successful -- try to allocate again
  193. }
  194. }
  195. /***
  196. *void *_heap_alloc_base(size_t size) - does actual allocation
  197. *
  198. *Purpose:
  199. * Same as malloc() except the new handler is not called.
  200. *
  201. *Entry:
  202. * See malloc
  203. *
  204. *Exit:
  205. * See malloc
  206. *
  207. *Exceptions:
  208. *
  209. *******************************************************************************/
  210. void * __cdecl _heap_alloc_base (size_t size)
  211. {
  212. #ifndef WINHEAP
  213. _PBLKDESC pdesc;
  214. _PBLKDESC pdesc2;
  215. #endif
  216. #ifdef HEAPHOOK
  217. // call heap hook if installed
  218. if (_heaphook)
  219. {
  220. void * pvReturn;
  221. if ((*_heaphook)(_HEAP_MALLOC, size, NULL, (void *)&pvReturn))
  222. return pvReturn;
  223. }
  224. #endif /* HEAPHOOK */
  225. #ifdef WINHEAP
  226. #ifndef _WIN64
  227. if ( __active_heap == __V6_HEAP )
  228. {
  229. void * pvReturn;
  230. if ( size <= __sbh_threshold )
  231. {
  232. #ifdef _MT
  233. _mlock( _HEAP_LOCK );
  234. __try {
  235. #endif
  236. pvReturn = __sbh_alloc_block((int)size);
  237. #ifdef _MT
  238. }
  239. __finally {
  240. _munlock( _HEAP_LOCK );
  241. }
  242. #endif
  243. if (pvReturn)
  244. return pvReturn;
  245. }
  246. }
  247. #ifdef CRTDLL
  248. else if ( __active_heap == __V5_HEAP )
  249. {
  250. void * pvReturn;
  251. /* round up to the nearest paragraph */
  252. if ( size )
  253. size = (size + _OLD_PARASIZE - 1) & ~(_OLD_PARASIZE - 1);
  254. else
  255. size = _OLD_PARASIZE;
  256. if ( size <= __old_sbh_threshold ) {
  257. #ifdef _MT
  258. _mlock(_HEAP_LOCK);
  259. __try {
  260. #endif
  261. pvReturn = __old_sbh_alloc_block(size >> _OLD_PARASHIFT);
  262. #ifdef _MT
  263. }
  264. __finally {
  265. _munlock(_HEAP_LOCK);
  266. }
  267. #endif
  268. if ( pvReturn != NULL )
  269. return pvReturn;
  270. }
  271. return HeapAlloc( _crtheap, 0, size );
  272. }
  273. #endif /* CRTDLL */
  274. #endif /* ndef _WIN64 */
  275. if (size == 0)
  276. size = 1;
  277. #ifndef _WIN64
  278. if (__active_heap != __SYSTEM_HEAP)
  279. size = (size + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1);
  280. #endif /* ndef _WIN64 */
  281. return HeapAlloc(_crtheap, 0, size);
  282. }
  283. #else /* WINHEAP */
  284. /* try to find a big enough free block
  285. */
  286. if ( (pdesc = _heap_search(size)) == NULL )
  287. {
  288. if ( _heap_grow(size) != -1 )
  289. {
  290. /* try finding a big enough free block again. the
  291. * success of the call to _heap_grow should guarantee
  292. * it, but...
  293. */
  294. if ( (pdesc = _heap_search(size)) == NULL )
  295. {
  296. /* something unexpected, and very bad, has
  297. * happened. abort!
  298. */
  299. _heap_abort();
  300. }
  301. }
  302. else
  303. return NULL;
  304. }
  305. /* carve the block into two pieces (if necessary). the first piece
  306. * shall be of the exact requested size, marked inuse and returned to
  307. * the caller. the leftover piece is to be marked free.
  308. */
  309. if ( _BLKSIZE(pdesc) != size ) {
  310. /* split up the block and free the leftover piece back to
  311. * the heap
  312. */
  313. if ( (pdesc2 = _heap_split_block(pdesc, size)) != NULL )
  314. _SET_FREE(pdesc2);
  315. }
  316. /* mark pdesc inuse
  317. */
  318. _SET_INUSE(pdesc);
  319. /* check proverdesc and reset, if necessary
  320. */
  321. _heap_desc.proverdesc = pdesc->pnextdesc;
  322. return( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) );
  323. }
  324. /***
  325. *_PBLKDESC _heap_split_block(pdesc, newsize) - split a heap allocation block
  326. * into two allocation blocks
  327. *
  328. *Purpose:
  329. * Split the allocation block described by pdesc into two blocks, the
  330. * first one being of newsize bytes.
  331. *
  332. * Notes: It is caller's responsibilty to set the status (i.e., free
  333. * or inuse) of the two new blocks, and to check and reset proverdesc
  334. * if necessary. See Exceptions (below) for additional requirements.
  335. *
  336. *Entry:
  337. * _PBLKDESC pdesc - pointer to the allocation block descriptor
  338. * size_t newsize - size for the first of the two sub-blocks (i.e.,
  339. * (i.e., newsize == _BLKSIZE(pdesc), on exit)
  340. *
  341. *Exit:
  342. * If successful, return a pointer to the descriptor for the leftover
  343. * block.
  344. * Otherwise, return NULL.
  345. *
  346. *Exceptions:
  347. * It is assumed pdesc points to a valid allocation block descriptor and
  348. * newsize is a valid heap block size as is (i.e., WITHOUT rounding). If
  349. * either of these of assumption is violated, _heap_split_block() will
  350. * likely corrupt the heap. Note also that _heap_split_block will simply
  351. * return to the caller if newsize >= _BLKSIZE(pdesc), on entry.
  352. *
  353. *******************************************************************************/
  354. _PBLKDESC __cdecl _heap_split_block (
  355. REG1 _PBLKDESC pdesc,
  356. size_t newsize
  357. )
  358. {
  359. REG2 _PBLKDESC pdesc2;
  360. _ASSERTE(("_heap_split_block: bad pdesc arg", _CHECK_PDESC(pdesc)));
  361. _ASSERTE(("_heap_split_block: bad newsize arg", _ROUND2(newsize,_GRANULARITY) == newsize));
  362. /* carve the block into two pieces (if possible). the first piece
  363. * is to be exactly newsize bytes.
  364. */
  365. if ( (_BLKSIZE(pdesc) > newsize) && ((pdesc2 = __getempty())
  366. != NULL) )
  367. {
  368. /* set it up to manage the second piece and link it in to
  369. * the list
  370. */
  371. pdesc2->pblock = (void *)((char *)_ADDRESS(pdesc) + newsize +
  372. _HDRSIZE);
  373. *(void **)(pdesc2->pblock) = pdesc2;
  374. pdesc2->pnextdesc = pdesc->pnextdesc;
  375. pdesc->pnextdesc = pdesc2;
  376. return pdesc2;
  377. }
  378. return NULL;
  379. }
  380. #endif /* WINHEAP */
  381. #endif /* _POSIX_ */