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.

742 lines
26 KiB

  1. /***
  2. *realloc.c - Reallocate a block of memory in the heap
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Defines the realloc() and _expand() functions.
  8. *
  9. *Revision History:
  10. * 10-25-89 GJF Module created.
  11. * 11-06-89 GJF Massively revised to handle 'tiling' and to properly
  12. * update proverdesc.
  13. * 11-10-89 GJF Added MTHREAD support.
  14. * 11-17-89 GJF Fixed pblck validation (i.e., conditional call to
  15. * _heap_abort())
  16. * 12-18-89 GJF Changed header file name to heap.h, also added explicit
  17. * _cdecl or _pascal to function defintions
  18. * 12-20-89 GJF Removed references to plastdesc
  19. * 01-04-90 GJF Fixed a couple of subtle and nasty bugs in _expand().
  20. * 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
  21. * <cruntime.h> and removed #include <register.h>.
  22. * 03-29-90 GJF Made _heap_expand_block() _CALLTYPE4.
  23. * 07-25-90 SBM Replaced <stdio.h> by <stddef.h>, replaced
  24. * <assertm.h> by <assert.h>
  25. * 09-28-90 GJF New-style function declarators.
  26. * 12-28-90 SRW Added cast of void * to char * for Mips C Compiler
  27. * 03-05-91 GJF Changed strategy for rover - old version available
  28. * by #define-ing _OLDROVER_.
  29. * 04-08-91 GJF Temporary hack for Win32/DOS folks - special version
  30. * of realloc that uses just malloc, _msize, memcpy and
  31. * free. Change conditioned on _WIN32DOS_.
  32. * 05-28-91 GJF Removed M_I386 conditionals and put in _WIN32_
  33. * conditionals to build non-tiling heap for Win32.
  34. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  35. * 08-06-93 SKS Fix bug in realloc() - if block cannot be expanded in
  36. * place, and call to malloc() fails, the code in this
  37. * routine was inadvertently freeing the sucessor block.
  38. * Reported by Phar Lap TNT team after MSVCNT was final.
  39. * 09-27-93 GJF Added checks of block size argument(s) against
  40. * _HEAP_MAXREQ. Removed old _CRUISER_ and _WIN32DOS_
  41. * support. Added some indenting to complicated exprs.
  42. * 12-10-93 GJF Replace 4 (bytes) with _GRANULARITY.
  43. * 03-02-94 GJF If _heap_split_block() returns failure, which it now
  44. * can, return the untrimmed allocation block.
  45. * 11-03-94 CFW Debug heap support.
  46. * 12-01-94 CFW Use malloc with new handler.
  47. * 02-06-95 CFW assert -> _ASSERTE.
  48. * 02-07-95 GJF Merged in Mac version. Temporarily #ifdef-ed out the
  49. * dbgint.h stuff. Removed obsolete _OLDROVER_ code.
  50. * 02-09-95 GJF Restored *_base names.
  51. * 05-01-95 GJF Spliced on winheap version.
  52. * 05-08-95 CFW Changed new handler scheme.
  53. * 05-22-95 GJF Test against _HEAP_MAXREQ before calling API.
  54. * 05-24-95 CFW Official ANSI C++ new handler added.
  55. * 03-05-96 GJF Added support for small-block heap.
  56. * 04-10-96 GJF Return type of __sbh_find_block, __sbh_resize_block
  57. * and __sbh_free_block changed to __map_t *.
  58. * 05-30-96 GJF Minor changes for latest version of small-block heap.
  59. * 05-22-97 RDK New small-block heap scheme implemented.
  60. * 09-26-97 BWT Fix POSIX
  61. * 11-05-97 GJF Small POSIX fix from Roger Lanser.
  62. * 12-17-97 GJF Exception-safe locking.
  63. * 05-22-98 JWM Support for KFrei's RTC work.
  64. * 07-28-98 JWM RTC update.
  65. * 09-30-98 GJF Bypass all small-block heap code when __sbh_initialized
  66. * is 0.
  67. * 11-16-98 GJF Merged in VC++ 5.0 version of small-block heap.
  68. * 12-18-98 GJF Changes for 64-bit size_t.
  69. * 03-30-99 GJF __sbh_alloc_block may have moved the header list
  70. * 05-01-99 PML Disable small-block heap for Win64.
  71. * 05-17-99 PML Remove all Macintosh support.
  72. * 05-26-99 KBF Updated RTC hook func params
  73. * 06-22-99 GJF Removed old small-block heap from static libs.
  74. * 08-04-00 PML Don't round allocation sizes when using system
  75. * heap (VS7#131005).
  76. *
  77. *******************************************************************************/
  78. #ifdef WINHEAP
  79. #include <cruntime.h>
  80. #include <malloc.h>
  81. #include <stdlib.h>
  82. #include <string.h>
  83. #include <winheap.h>
  84. #include <windows.h>
  85. #include <internal.h>
  86. #include <mtdll.h>
  87. #include <dbgint.h>
  88. #include <rtcsup.h>
  89. /***
  90. *void *realloc(pblock, newsize) - reallocate a block of memory in the heap
  91. *
  92. *Purpose:
  93. * Reallocates a block in the heap to newsize bytes. newsize may be
  94. * either greater or less than the original size of the block. The
  95. * reallocation may result in moving the block as well as changing
  96. * the size. If the block is moved, the contents of the original block
  97. * are copied over.
  98. *
  99. * Special ANSI Requirements:
  100. *
  101. * (1) realloc(NULL, newsize) is equivalent to malloc(newsize)
  102. *
  103. * (2) realloc(pblock, 0) is equivalent to free(pblock) (except that
  104. * NULL is returned)
  105. *
  106. * (3) if the realloc() fails, the object pointed to by pblock is left
  107. * unchanged
  108. *
  109. *Entry:
  110. * void *pblock - pointer to block in the heap previously allocated
  111. * by a call to malloc(), realloc() or _expand().
  112. *
  113. * size_t newsize - requested size for the re-allocated block
  114. *
  115. *Exit:
  116. * Success: Pointer to the re-allocated memory block
  117. * Failure: NULL
  118. *
  119. *Uses:
  120. *
  121. *Exceptions:
  122. * If pblock does not point to a valid allocation block in the heap,
  123. * realloc() will behave unpredictably and probably corrupt the heap.
  124. *
  125. *******************************************************************************/
  126. void * __cdecl _realloc_base (void * pBlock, size_t newsize)
  127. {
  128. #ifdef _POSIX_
  129. return HeapReAlloc(_crtheap, 0, pBlock, newsize);
  130. #else
  131. void * pvReturn;
  132. size_t origSize = newsize;
  133. // if ptr is NULL, call malloc
  134. if (pBlock == NULL)
  135. return(_malloc_base(newsize));
  136. // if ptr is nonNULL and size is zero, call free and return NULL
  137. if (newsize == 0)
  138. {
  139. _free_base(pBlock);
  140. return(NULL);
  141. }
  142. #ifdef HEAPHOOK
  143. // call heap hook if installed
  144. if (_heaphook)
  145. {
  146. if ((*_heaphook)(_HEAP_REALLOC, newsize, pBlock, (void *)&pvReturn))
  147. return pvReturn;
  148. }
  149. #endif /* HEAPHOOK */
  150. #ifndef _WIN64
  151. if ( __active_heap == __V6_HEAP )
  152. {
  153. PHEADER pHeader;
  154. size_t oldsize;
  155. for (;;)
  156. {
  157. pvReturn = NULL;
  158. if (newsize <= _HEAP_MAXREQ)
  159. {
  160. #ifdef _MT
  161. _mlock( _HEAP_LOCK );
  162. __try
  163. {
  164. #endif
  165. // test if current block is in the small-block heap
  166. if ((pHeader = __sbh_find_block(pBlock)) != NULL)
  167. {
  168. // if the new size is not over __sbh_threshold, attempt
  169. // to reallocate within the small-block heap
  170. if (newsize <= __sbh_threshold)
  171. {
  172. if (__sbh_resize_block(pHeader, pBlock, (int)newsize))
  173. pvReturn = pBlock;
  174. else if ((pvReturn = __sbh_alloc_block((int)newsize)) != NULL)
  175. {
  176. oldsize = ((PENTRY)((char *)pBlock -
  177. sizeof(int)))->sizeFront - 1;
  178. memcpy(pvReturn, pBlock, __min(oldsize, newsize));
  179. // headers may have moved, get pHeader again
  180. pHeader = __sbh_find_block(pBlock);
  181. __sbh_free_block(pHeader, pBlock);
  182. }
  183. }
  184. // If the reallocation has not been (successfully)
  185. // performed in the small-block heap, try to allocate
  186. // a new block with HeapAlloc.
  187. if (pvReturn == NULL)
  188. {
  189. if (newsize == 0)
  190. newsize = 1;
  191. newsize = (newsize + BYTES_PER_PARA - 1) &
  192. ~(BYTES_PER_PARA - 1);
  193. if ((pvReturn = HeapAlloc(_crtheap, 0, newsize)) != NULL)
  194. {
  195. oldsize = ((PENTRY)((char *)pBlock -
  196. sizeof(int)))->sizeFront - 1;
  197. memcpy(pvReturn, pBlock, __min(oldsize, newsize));
  198. __sbh_free_block(pHeader, pBlock);
  199. }
  200. }
  201. }
  202. #ifdef _MT
  203. }
  204. __finally
  205. {
  206. _munlock( _HEAP_LOCK );
  207. }
  208. #endif
  209. // the current block is NOT in the small block heap iff pHeader
  210. // is NULL
  211. if ( pHeader == NULL )
  212. {
  213. if (newsize == 0)
  214. newsize = 1;
  215. newsize = (newsize + BYTES_PER_PARA - 1) &
  216. ~(BYTES_PER_PARA - 1);
  217. pvReturn = HeapReAlloc(_crtheap, 0, pBlock, newsize);
  218. }
  219. }
  220. if ( pvReturn || _newmode == 0)
  221. {
  222. if (pvReturn)
  223. {
  224. RTCCALLBACK(_RTC_Free_hook, (pBlock, 0));
  225. RTCCALLBACK(_RTC_Allocate_hook, (pvReturn, newsize, 0));
  226. }
  227. return pvReturn;
  228. }
  229. // call installed new handler
  230. if (!_callnewh(newsize))
  231. return NULL;
  232. // new handler was successful -- try to allocate again
  233. }
  234. }
  235. #ifdef CRTDLL
  236. else if ( __active_heap == __V5_HEAP )
  237. {
  238. __old_sbh_region_t *preg;
  239. __old_sbh_page_t * ppage;
  240. __old_page_map_t * pmap;
  241. size_t oldsize;
  242. // round up to the nearest paragrap
  243. if ( newsize <= _HEAP_MAXREQ )
  244. if ( newsize > 0 )
  245. newsize = (newsize + _OLD_PARASIZE - 1) & ~(_OLD_PARASIZE - 1);
  246. else
  247. newsize = _OLD_PARASIZE;
  248. for (;;)
  249. {
  250. pvReturn = NULL;
  251. if ( newsize <= _HEAP_MAXREQ )
  252. {
  253. #ifdef _MT
  254. _mlock( _HEAP_LOCK );
  255. __try
  256. {
  257. #endif
  258. if ( (pmap = __old_sbh_find_block(pBlock, &preg, &ppage)) != NULL )
  259. {
  260. // If the new size falls below __sbh_threshold, try to
  261. // carry out the reallocation within the small-block
  262. // heap.
  263. if ( newsize < __old_sbh_threshold )
  264. {
  265. if ( __old_sbh_resize_block(preg, ppage, pmap,
  266. newsize >> _OLD_PARASHIFT) )
  267. {
  268. pvReturn = pBlock;
  269. }
  270. else if ( (pvReturn = __old_sbh_alloc_block(newsize >>
  271. _OLD_PARASHIFT)) != NULL )
  272. {
  273. oldsize = ((size_t)(*pmap)) << _OLD_PARASHIFT ;
  274. memcpy(pvReturn, pBlock, __min(oldsize, newsize));
  275. __old_sbh_free_block(preg, ppage, pmap);
  276. }
  277. }
  278. // If the reallocation has not been (successfully)
  279. // performed in the small-block heap, try to allocate a
  280. // new block with HeapAlloc.
  281. if ( (pvReturn == NULL) &&
  282. ((pvReturn = HeapAlloc(_crtheap, 0, newsize)) != NULL) )
  283. {
  284. oldsize = ((size_t)(*pmap)) << _OLD_PARASHIFT;
  285. memcpy(pvReturn, pBlock, __min(oldsize, newsize));
  286. __old_sbh_free_block(preg, ppage, pmap);
  287. }
  288. }
  289. else
  290. {
  291. pvReturn = HeapReAlloc(_crtheap, 0, pBlock, newsize);
  292. }
  293. #ifdef _MT
  294. }
  295. __finally
  296. {
  297. _munlock(_HEAP_LOCK);
  298. }
  299. #endif
  300. }
  301. if ( pvReturn || _newmode == 0)
  302. {
  303. if (pvReturn)
  304. {
  305. RTCCALLBACK(_RTC_Free_hook, (pBlock, 0));
  306. RTCCALLBACK(_RTC_Allocate_hook, (pvReturn, newsize, 0));
  307. }
  308. return pvReturn;
  309. }
  310. // call installed new handler
  311. if (!_callnewh(newsize))
  312. return NULL;
  313. // new handler was successful -- try to allocate again
  314. }
  315. }
  316. #endif /* CRTDLL */
  317. else // __active_heap == __SYSTEM_HEAP )
  318. #endif /* ndef _WIN64 */
  319. {
  320. for (;;) {
  321. pvReturn = NULL;
  322. if (newsize <= _HEAP_MAXREQ)
  323. {
  324. if (newsize == 0)
  325. newsize = 1;
  326. pvReturn = HeapReAlloc(_crtheap, 0, pBlock, newsize);
  327. }
  328. if ( pvReturn || _newmode == 0)
  329. {
  330. if (pvReturn)
  331. {
  332. RTCCALLBACK(_RTC_Free_hook, (pBlock, 0));
  333. RTCCALLBACK(_RTC_Allocate_hook, (pvReturn, newsize, 0));
  334. }
  335. return pvReturn;
  336. }
  337. // call installed new handler
  338. if (!_callnewh(newsize))
  339. return NULL;
  340. // new handler was successful -- try to allocate again
  341. }
  342. }
  343. #endif /* ndef _POSIX_ */
  344. }
  345. #else /* ndef WINHEAP */
  346. #include <cruntime.h>
  347. #include <heap.h>
  348. #include <malloc.h>
  349. #include <mtdll.h>
  350. #include <stddef.h>
  351. #include <string.h>
  352. #include <dbgint.h>
  353. /* useful macro to compute the size of an allocation block given both a
  354. * pointer to the descriptor and a pointer to the user area of the block
  355. * (more efficient variant of _BLKSIZE macro, given the extra information)
  356. */
  357. #define BLKSZ(pdesc_m,pblock_m) ((unsigned)_ADDRESS((pdesc_m)->pnextdesc) - \
  358. (unsigned)(pblock_m))
  359. /* expand an allocation block, in place, up to or beyond a specified size
  360. * by coalescing it with subsequent free blocks (if possible)
  361. */
  362. static int __cdecl _heap_expand_block(_PBLKDESC, size_t *, size_t);
  363. /***
  364. *void *realloc(void *pblock, size_t newsize) - reallocate a block of memory in
  365. * the heap
  366. *
  367. *Purpose:
  368. * Re-allocates a block in the heap to newsize bytes. newsize may be
  369. * either greater or less than the original size of the block. The
  370. * re-allocation may result in moving the block as well as changing
  371. * the size. If the block is moved, the contents of the original block
  372. * are copied over.
  373. *
  374. * Special ANSI Requirements:
  375. *
  376. * (1) realloc(NULL, newsize) is equivalent to malloc(newsize)
  377. *
  378. * (2) realloc(pblock, 0) is equivalent to free(pblock) (except that
  379. * NULL is returned)
  380. *
  381. * (3) if the realloc() fails, the object pointed to by pblock is left
  382. * unchanged
  383. *
  384. * Special Notes For Multi-thread: The heap is locked immediately prior
  385. * to assigning pdesc. This is after special cases (1) and (2), listed
  386. * above, are taken care of. The lock is released immediately prior to
  387. * the final return statement.
  388. *
  389. *Entry:
  390. * void *pblock - pointer to block in the heap previously allocated
  391. * by a call to malloc(), realloc() or _expand().
  392. *
  393. * size_t newsize - requested size for the re-allocated block
  394. *
  395. *Exit:
  396. * Success: Pointer to the re-allocated memory block
  397. * Failure: NULL
  398. *
  399. *Uses:
  400. *
  401. *Exceptions:
  402. * If pblock does not point to a valid allocation block in the heap,
  403. * realloc() will behave unpredictably and probably corrupt the heap.
  404. *
  405. *******************************************************************************/
  406. void * __cdecl _realloc_base (
  407. REG1 void *pblock,
  408. size_t newsize
  409. )
  410. {
  411. REG2 _PBLKDESC pdesc;
  412. _PBLKDESC pdesc2;
  413. void *retp;
  414. size_t oldsize;
  415. size_t currsize;
  416. /* special cases, handling mandated by ANSI
  417. */
  418. if ( pblock == NULL )
  419. /* just do a malloc of newsize bytes and return a pointer to
  420. * the new block
  421. */
  422. return( _malloc_base(newsize) );
  423. if ( newsize == 0 ) {
  424. /* free the block and return NULL
  425. */
  426. _free_base(pblock);
  427. return( NULL );
  428. }
  429. /* make newsize a valid allocation block size (i.e., round up to the
  430. * nearest whole number of dwords)
  431. */
  432. newsize = _ROUND2(newsize, _GRANULARITY);
  433. #ifdef HEAPHOOK
  434. /* call heap hook if installed */
  435. if (_heaphook) {
  436. if ((*_heaphook)(_HEAP_REALLOC, newsize, pblock, (void *)&retp))
  437. return retp;
  438. }
  439. #endif /* HEAPHOOK */
  440. /* if multi-thread support enabled, lock the heap here
  441. */
  442. _mlock(_HEAP_LOCK);
  443. /* set pdesc to point to the descriptor for *pblock
  444. */
  445. pdesc = _BACKPTR(pblock);
  446. if ( _ADDRESS(pdesc) != ((char *)pblock - _HDRSIZE) )
  447. _heap_abort();
  448. /* see if pblock is big enough already, or can be expanded (in place)
  449. * to be big enough.
  450. */
  451. if ( ((oldsize = currsize = BLKSZ(pdesc, pblock)) > newsize) ||
  452. (_heap_expand_block(pdesc, &currsize, newsize) == 0) ) {
  453. /* if necessary, mark pdesc as inuse
  454. */
  455. if ( _IS_FREE(pdesc) ) {
  456. _SET_INUSE(pdesc);
  457. }
  458. /* trim pdesc down to be exactly newsize bytes, if necessary
  459. */
  460. if ( (currsize > newsize) &&
  461. ((pdesc2 = _heap_split_block(pdesc, newsize)) != NULL) )
  462. {
  463. _SET_FREE(pdesc2);
  464. }
  465. retp = pblock;
  466. goto realloc_done;
  467. }
  468. /* try malloc-ing a new block of the requested size. if successful,
  469. * copy over the data from the original block and free it.
  470. */
  471. if ( (retp = _malloc_base(newsize)) != NULL ) {
  472. memcpy(retp, pblock, oldsize);
  473. _free_base_lk(pblock);
  474. }
  475. /* else if unsuccessful, return retp (== NULL) */
  476. realloc_done:
  477. /* if multi-thread support is enabled, unlock the heap here
  478. */
  479. _munlock(_HEAP_LOCK);
  480. return(retp);
  481. }
  482. /***
  483. *void *_expand(void *pblock, size_t newsize) - expand/contract a block of memory
  484. * in the heap
  485. *
  486. *Purpose:
  487. * Resizes a block in the heap to newsize bytes. newsize may be either
  488. * greater (expansion) or less (contraction) than the original size of
  489. * the block. The block is NOT moved. In the case of expansion, if the
  490. * block cannot be expanded to newsize bytes, it is expanded as much as
  491. * possible.
  492. *
  493. * Special Notes For Multi-thread: The heap is locked just before pdesc
  494. * is assigned and unlocked immediately prior to the return statement.
  495. *
  496. *Entry:
  497. * void *pblock - pointer to block in the heap previously allocated
  498. * by a call to malloc(), realloc() or _expand().
  499. *
  500. * size_t newsize - requested size for the resized block
  501. *
  502. *Exit:
  503. * Success: Pointer to the resized memory block (i.e., pblock)
  504. * Failure: NULL
  505. *
  506. *Uses:
  507. *
  508. *Exceptions:
  509. * If pblock does not point to a valid allocation block in the heap,
  510. * _expand() will behave unpredictably and probably corrupt the heap.
  511. *
  512. *******************************************************************************/
  513. void * __cdecl _expand_base (
  514. REG1 void *pblock,
  515. size_t newsize
  516. )
  517. {
  518. REG2 _PBLKDESC pdesc;
  519. _PBLKDESC pdesc2;
  520. void *retp;
  521. size_t oldsize;
  522. size_t currsize;
  523. int index;
  524. /* make newsize a valid allocation block size (i.e., round up to the
  525. * nearest whole number of dwords)
  526. */
  527. newsize = _ROUND2(newsize, _GRANULARITY);
  528. #ifdef HEAPHOOK
  529. /* call heap hook if installed */
  530. if (_heaphook) {
  531. if ((*_heaphook)(_HEAP_EXPAND, newsize, pblock, (void *)&retp))
  532. return retp;
  533. }
  534. #endif /* HEAPHOOK */
  535. retp = pblock;
  536. /* validate size */
  537. if ( newsize > _HEAP_MAXREQ )
  538. newsize = _HEAP_MAXREQ;
  539. /* if multi-thread support enabled, lock the heap here
  540. */
  541. _mlock(_HEAP_LOCK);
  542. /* set pdesc to point to the descriptor for *pblock
  543. */
  544. pdesc = _BACKPTR(pblock);
  545. /* see if pblock is big enough already, or can be expanded (in place)
  546. * to be big enough.
  547. */
  548. if ( ((oldsize = currsize = BLKSZ(pdesc, pblock)) >= newsize) ||
  549. (_heap_expand_block(pdesc, &currsize, newsize) == 0) ) {
  550. /* pblock is (now) big enough. trim it down, if necessary
  551. */
  552. if ( (currsize > newsize) &&
  553. ((pdesc2 = _heap_split_block(pdesc, newsize)) != NULL) )
  554. {
  555. _SET_FREE(pdesc2);
  556. currsize = newsize;
  557. }
  558. goto expand_done;
  559. }
  560. /* if the heap block is at the end of a region, attempt to grow the
  561. * region
  562. */
  563. if ( (pdesc->pnextdesc == &_heap_desc.sentinel) ||
  564. _IS_DUMMY(pdesc->pnextdesc) ) {
  565. /* look up the region index
  566. */
  567. for ( index = 0 ; index < _HEAP_REGIONMAX ; index++ )
  568. if ( (_heap_regions[index]._regbase < pblock) &&
  569. (((char *)(_heap_regions[index]._regbase) +
  570. _heap_regions[index]._currsize) >=
  571. (char *)pblock) )
  572. break;
  573. /* make sure a valid region index was obtained (pblock could
  574. * lie in a portion of heap memory donated by a user call to
  575. * _heapadd(), which therefore would not appear in the region
  576. * table)
  577. */
  578. if ( index == _HEAP_REGIONMAX ) {
  579. retp = NULL;
  580. goto expand_done;
  581. }
  582. /* try growing the region. the difference between newsize and
  583. * the current size of the block, rounded up to the nearest
  584. * whole number of pages, is the amount the region needs to
  585. * be grown. if successful, try expanding the block again
  586. */
  587. if ( (_heap_grow_region(index, _ROUND2(newsize - currsize,
  588. _PAGESIZE_)) == 0) &&
  589. (_heap_expand_block(pdesc, &currsize, newsize) == 0) )
  590. {
  591. /* pblock is (now) big enough. trim it down to be
  592. * exactly size bytes, if necessary
  593. */
  594. if ( (currsize > newsize) && ((pdesc2 =
  595. _heap_split_block(pdesc, newsize)) != NULL) )
  596. {
  597. _SET_FREE(pdesc2);
  598. currsize = newsize;
  599. }
  600. }
  601. else
  602. retp = NULL;
  603. }
  604. else
  605. retp = NULL;
  606. expand_done:
  607. /* if multi-thread support is enabled, unlock the heap here
  608. */
  609. _munlock(_HEAP_LOCK);
  610. return(retp);
  611. }
  612. /***
  613. *int _heap_expand_block(pdesc, pcurrsize, newsize) - expand an allocation block
  614. * in place (without trying to 'grow' the heap)
  615. *
  616. *Purpose:
  617. *
  618. *Entry:
  619. * _PBLKDESC pdesc - pointer to the allocation block descriptor
  620. * size_t *pcurrsize - pointer to size of the allocation block (i.e.,
  621. * *pcurrsize == _BLKSIZE(pdesc), on entry)
  622. * size_t newsize - requested minimum size for the expanded allocation
  623. * block (i.e., newsize >= _BLKSIZE(pdesc), on exit)
  624. *
  625. *Exit:
  626. * Success: 0
  627. * Failure: -1
  628. * In either case, *pcurrsize is updated with the new size of the block
  629. *
  630. *Exceptions:
  631. * It is assumed that pdesc points to a valid allocation block descriptor.
  632. * It is also assumed that _BLKSIZE(pdesc) == *pcurrsize on entry. If
  633. * either of these assumptions is violated, _heap_expand_block will almost
  634. * certainly trash the heap.
  635. *
  636. *******************************************************************************/
  637. static int __cdecl _heap_expand_block (
  638. REG1 _PBLKDESC pdesc,
  639. REG3 size_t *pcurrsize,
  640. size_t newsize
  641. )
  642. {
  643. REG2 _PBLKDESC pdesc2;
  644. _ASSERTE(("_heap_expand_block: bad pdesc arg", _CHECK_PDESC(pdesc)));
  645. _ASSERTE(("_heap_expand_block: bad pcurrsize arg", *pcurrsize == _BLKSIZE(pdesc)));
  646. for ( pdesc2 = pdesc->pnextdesc ; _IS_FREE(pdesc2) ;
  647. pdesc2 = pdesc->pnextdesc ) {
  648. /* coalesce with pdesc. check for special case of pdesc2
  649. * being proverdesc.
  650. */
  651. pdesc->pnextdesc = pdesc2->pnextdesc;
  652. if ( pdesc2 == _heap_desc.proverdesc )
  653. _heap_desc.proverdesc = pdesc;
  654. /* update *pcurrsize, place *pdesc2 on the empty descriptor
  655. * list and see if the coalesced block is now big enough
  656. */
  657. *pcurrsize += _MEMSIZE(pdesc2);
  658. _PUTEMPTY(pdesc2)
  659. }
  660. if ( *pcurrsize >= newsize )
  661. return(0);
  662. else
  663. return(-1);
  664. }
  665. #endif /* WINHEAP */