windows-nt/Source/XPSP1/NT/base/crts/crtw32/heap/expand.c
2020-09-26 16:20:57 +08:00

233 lines
8 KiB
C

/***
*expand.c - Win32 expand heap routine
*
* Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
*
*Purpose:
*
*Revision History:
* 01-15-92 JCR Module created.
* 02-04-92 GJF Replaced windows.h with oscalls.h.
* 05-06-92 DJM ifndef out of POSIX build.
* 09-23-92 SRW Change winheap code to call NT directly always
* 10-15-92 SKS Removed the ill-named HEAP_GROWTH_ALLOWED flag
* which was causing a bug: _expand was behaving like
* realloc(), by moving the block when it could not be
* grown in place. _expand() must NEVER move the block.
* Also added a safety check to work around a bug in
* HeapReAlloc, where it returns success even
* when it fails to grow the block in place.
* 10-28-92 SRW Change winheap code to call Heap????Ex calls
* 11-05-92 SKS Change name of variable "CrtHeap" to "_crtheap"
* 11-07-92 SRW _NTIDW340 replaced by linkopts\betacmp.c
* 11-16-92 SRW Heap???Ex functions renamed to Heap???
* 10-21-93 GJF Replace _CALLTYPE1 with _cdecl. Cleaned up format.
* 04-06-95 GJF Added support for debug heap.
* 04-29-95 GJF Copied over from winheap and made conditional on
* WINHEAP.
* 05-22-95 GJF Test against _HEAP_MAXREQ before calling API. Also,
* removed workaround for long-ago NT problem.
* 05-24-95 CFW Official ANSI C++ new handler added.
* 05-23-95 GJF Really removed workaround this time...
* 03-04-96 GJF Added support for small-block heap. Moved heaphook
* invocation to the very start of the function.
* 04-10-96 GJF Return type of __sbh_find_block and __sbh_resize_block
* changed to __map_t *.
* 05-30-96 GJF Minor changes for latest version of small-block heap.
* 05-22-97 RDK New small-block heap scheme implemented.
* 09-26-97 BWT Fix POSIX
* 11-05-97 GJF Small POSIX fix from Roger Lanser.
* 12-17-97 GJF Exception-safe locking.
* 07-28-98 JWM RTC update.
* 09-29-98 GJF Bypass all small-block heap code when __sbh_initialized
* is 0.
* 11-16-98 GJF Merged in VC++ 5.0 version of small-block heap.
* 12-02-98 GJF One too many munlocks!
* 12-18-98 GJF Changes for 64-bit size_t.
* 05-01-99 PML Disable small-block heap for Win64.
* 05-26-99 KBF Updated RTC hook func params
* 06-21-99 GJF Removed old small-block heap from static libs.
* 08-04-00 PML Don't round allocation sizes when using system
* heap (VS7#131005).
*
*******************************************************************************/
#ifdef WINHEAP
#include <cruntime.h>
#include <malloc.h>
#include <winheap.h>
#include <windows.h>
#include <mtdll.h>
#include <dbgint.h>
#include <rtcsup.h>
/***
*void *_expand(void *pblck, size_t newsize) - expand/contract a block of memory
* in the heap
*
*Purpose:
* Resizes a block in the heap to newsize bytes. newsize may be either
* greater (expansion) or less (contraction) than the original size of
* the block. The block is NOT moved.
*
* NOTES:
*
* (1) In this implementation, if the block cannot be grown to the
* desired size, the resulting block will NOT be grown to the max
* possible size. (That is, either it works or it doesn't.)
*
* (2) Unlike other implementations, you can NOT pass a previously
* freed block to this routine and expect it to work.
*
*Entry:
* void *pblck - pointer to block in the heap previously allocated
* by a call to malloc(), realloc() or _expand().
*
* size_t newsize - requested size for the resized block
*
*Exit:
* Success: Pointer to the resized memory block (i.e., pblck)
* Failure: NULL
*
*Uses:
*
*Exceptions:
* If pblck does not point to a valid allocation block in the heap,
* _expand() will behave unpredictably and probably corrupt the heap.
*
*******************************************************************************/
void * __cdecl _expand_base (void * pBlock, size_t newsize)
{
#ifdef _POSIX_
return (HeapReAlloc( _crtheap,
HEAP_REALLOC_IN_PLACE_ONLY,
pBlock,
(DWORD)newsize ));
#else
void * pvReturn;
#ifdef HEAPHOOK
/* call heap hook if installed */
if (_heaphook)
{
void * pvReturn;
if ((*_heaphook)(_HEAP_EXPAND, newsize, pBlock, (void *)&pvReturn))
return pvReturn;
}
#endif /* HEAPHOOK */
/* validate size */
if ( newsize > _HEAP_MAXREQ )
return NULL;
#ifndef _WIN64
if ( __active_heap == __V6_HEAP )
{
PHEADER pHeader;
#ifdef _MT
_mlock( _HEAP_LOCK );
__try {
#endif
// if allocation block lies within the small-block heap,
// try to resize it there
if ((pHeader = __sbh_find_block(pBlock)) != NULL)
{
pvReturn = NULL;
if ( (newsize <= __sbh_threshold) &&
__sbh_resize_block(pHeader, pBlock, (int)newsize) )
pvReturn = pBlock;
}
#ifdef _MT
}
__finally {
_munlock( _HEAP_LOCK );
}
#endif
if ( pHeader == NULL )
{
// force nonzero size and round up to next paragraph
if (newsize == 0)
newsize = 1;
newsize = (newsize + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1);
pvReturn = HeapReAlloc(_crtheap, HEAP_REALLOC_IN_PLACE_ONLY,
pBlock, newsize);
}
}
#ifdef CRTDLL
else if ( __active_heap == __V5_HEAP )
{
__old_sbh_region_t *preg;
__old_sbh_page_t * ppage;
__old_page_map_t * pmap;
// force nonzero size and round up to next paragraph
if (newsize == 0)
newsize = 1;
newsize = (newsize + _OLD_PARASIZE - 1) & ~(_OLD_PARASIZE - 1);
#ifdef _MT
_mlock(_HEAP_LOCK);
__try {
#endif
pmap = __old_sbh_find_block(pBlock, &preg, &ppage);
// allocation block lies within the small-block heap, try to resize
// it there.
if ( pmap != NULL )
{
// *pBlock lies within the small-block heap, try to resize it
// there
pvReturn = NULL;
if ( (newsize <= __old_sbh_threshold) &&
__old_sbh_resize_block(preg, ppage, pmap,
newsize >> _OLD_PARASHIFT) )
pvReturn = pBlock;
RTCCALLBACK(_RTC_Free_hook, (pBlock, 0));
RTCCALLBACK(_RTC_Allocate_hook, (pvReturn, newsize, 0));
return pvReturn;
}
#ifdef _MT
}
__finally {
_munlock(_HEAP_LOCK);
}
#endif
if ( pmap == NULL )
pvReturn = HeapReAlloc(_crtheap, HEAP_REALLOC_IN_PLACE_ONLY,
pBlock, newsize);
}
#endif /* CRTDLL */
else // __active_heap == __SYSTEM_HEAP
#endif /* ndef _WIN64 */
{
// force nonzero size
if (newsize == 0)
newsize = 1;
pvReturn = HeapReAlloc(_crtheap, HEAP_REALLOC_IN_PLACE_ONLY,
pBlock, newsize);
}
if (pvReturn)
{
RTCCALLBACK(_RTC_Free_hook, (pBlock, 0));
RTCCALLBACK(_RTC_Allocate_hook, (pvReturn, newsize, 0));
}
return pvReturn;
#endif /* _POSIX_ */
}
#endif /* WINHEAP */