home *** CD-ROM | disk | FTP | other *** search
- /***
- *realloc.c - Reallocate a block of memory in the heap
- *
- * Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
- *
- *Purpose:
- * Defines the realloc() and _expand() functions.
- *
- *******************************************************************************/
-
- #ifdef WINHEAP
-
- #include <cruntime.h>
- #include <malloc.h>
- #include <stdlib.h>
- #include <string.h>
- #include <winheap.h>
- #include <windows.h>
- #include <internal.h>
- #include <mtdll.h>
- #include <dbgint.h>
-
-
- /***
- *void *realloc(pblock, newsize) - reallocate a block of memory in the heap
- *
- *Purpose:
- * Reallocates a block in the heap to newsize bytes. newsize may be
- * either greater or less than the original size of the block. The
- * reallocation may result in moving the block as well as changing
- * the size. If the block is moved, the contents of the original block
- * are copied over.
- *
- * Special ANSI Requirements:
- *
- * (1) realloc(NULL, newsize) is equivalent to malloc(newsize)
- *
- * (2) realloc(pblock, 0) is equivalent to free(pblock) (except that
- * NULL is returned)
- *
- * (3) if the realloc() fails, the object pointed to by pblock is left
- * unchanged
- *
- *Entry:
- * void *pblock - pointer to block in the heap previously allocated
- * by a call to malloc(), realloc() or _expand().
- *
- * size_t newsize - requested size for the re-allocated block
- *
- *Exit:
- * Success: Pointer to the re-allocated memory block
- * Failure: NULL
- *
- *Uses:
- *
- *Exceptions:
- * If pblock does not point to a valid allocation block in the heap,
- * realloc() will behave unpredictably and probably corrupt the heap.
- *
- *******************************************************************************/
-
- void * __cdecl _realloc_base (void * pBlock, size_t newsize)
- {
- PHEADER pHeader;
- void * pvReturn;
- size_t oldsize;
-
- // if ptr is NULL, call malloc
- if (pBlock == NULL)
- return(_malloc_base(newsize));
-
- // if ptr is nonNULL and size is zero, call free and return NULL
- if (newsize == 0)
- {
- _free_base(pBlock);
- return(NULL);
- }
-
-
- for (;;) {
-
- pvReturn = NULL;
- if (newsize <= _HEAP_MAXREQ)
- {
- _mlock(_HEAP_LOCK);
-
- // test if current block is in the small-block heap
- if ((pHeader = __sbh_find_block(pBlock)) != NULL)
- {
- // if the new size is not over __sbh_threshold, attempt
- // to reallocate within the small-block heap
- if (newsize <= __sbh_threshold)
- {
- if (__sbh_resize_block(pHeader, pBlock, newsize))
- pvReturn = pBlock;
- else if ((pvReturn = __sbh_alloc_block(newsize)) != NULL)
- {
- oldsize = ((PENTRY)((char *)pBlock -
- sizeof(int)))->sizeFront - 1;
- memcpy(pvReturn, pBlock, __min(oldsize, newsize));
- __sbh_free_block(pHeader, pBlock);
- }
- }
-
- // If the reallocation has not been (successfully)
- // performed in the small-block heap, try to allocate
- // a new block with HeapAlloc.
- if (pvReturn == NULL)
- {
- if (newsize == 0)
- newsize = 1;
- newsize = (newsize + BYTES_PER_PARA - 1) &
- ~(BYTES_PER_PARA - 1);
- if ((pvReturn = HeapAlloc(_crtheap, 0, newsize)) != NULL)
- {
- oldsize = ((PENTRY)((char *)pBlock -
- sizeof(int)))->sizeFront - 1;
- memcpy(pvReturn, pBlock, __min(oldsize, newsize));
- __sbh_free_block(pHeader, pBlock);
- }
- }
- _munlock(_HEAP_LOCK);
- }
- else
- {
- _munlock(_HEAP_LOCK);
- if (newsize == 0)
- newsize = 1;
- newsize = (newsize + BYTES_PER_PARA - 1) &
- ~(BYTES_PER_PARA - 1);
- pvReturn = HeapReAlloc(_crtheap, 0, pBlock, newsize);
- }
- }
-
- if ( pvReturn || _newmode == 0)
- return pvReturn;
-
- // call installed new handler
- if (!_callnewh(newsize))
- return NULL;
-
- // new handler was successful -- try to allocate again
- }
- }
-
- #else /* WINHEAP */
-
-
- #include <cruntime.h>
- #include <heap.h>
- #include <malloc.h>
- #include <mtdll.h>
- #include <stddef.h>
- #include <string.h>
- #include <dbgint.h>
-
- #if defined (_M_MPPC) || defined (_M_M68K)
- #include <macos\memory.h> // Mac OS interface header
- #endif /* defined (_M_MPPC) || defined (_M_M68K) */
-
- /* useful macro to compute the size of an allocation block given both a
- * pointer to the descriptor and a pointer to the user area of the block
- * (more efficient variant of _BLKSIZE macro, given the extra information)
- */
- #define BLKSZ(pdesc_m,pblock_m) ((unsigned)_ADDRESS((pdesc_m)->pnextdesc) - \
- (unsigned)(pblock_m))
-
- /* expand an allocation block, in place, up to or beyond a specified size
- * by coalescing it with subsequent free blocks (if possible)
- */
- static int __cdecl _heap_expand_block(_PBLKDESC, size_t *, size_t);
-
- #if defined (_M_MPPC) || defined (_M_M68K)
- extern Handle hHeapRegions;
- extern int _heap_region_table_cur;
- #endif /* defined (_M_MPPC) || defined (_M_M68K) */
-
- /***
- *void *realloc(void *pblock, size_t newsize) - reallocate a block of memory in
- * the heap
- *
- *Purpose:
- * Re-allocates a block in the heap to newsize bytes. newsize may be
- * either greater or less than the original size of the block. The
- * re-allocation may result in moving the block as well as changing
- * the size. If the block is moved, the contents of the original block
- * are copied over.
- *
- * Special ANSI Requirements:
- *
- * (1) realloc(NULL, newsize) is equivalent to malloc(newsize)
- *
- * (2) realloc(pblock, 0) is equivalent to free(pblock) (except that
- * NULL is returned)
- *
- * (3) if the realloc() fails, the object pointed to by pblock is left
- * unchanged
- *
- * Special Notes For Multi-thread: The heap is locked immediately prior
- * to assigning pdesc. This is after special cases (1) and (2), listed
- * above, are taken care of. The lock is released immediately prior to
- * the final return statement.
- *
- *Entry:
- * void *pblock - pointer to block in the heap previously allocated
- * by a call to malloc(), realloc() or _expand().
- *
- * size_t newsize - requested size for the re-allocated block
- *
- *Exit:
- * Success: Pointer to the re-allocated memory block
- * Failure: NULL
- *
- *Uses:
- *
- *Exceptions:
- * If pblock does not point to a valid allocation block in the heap,
- * realloc() will behave unpredictably and probably corrupt the heap.
- *
- *******************************************************************************/
-
- void * __cdecl _realloc_base (
- REG1 void *pblock,
- size_t newsize
- )
- {
- REG2 _PBLKDESC pdesc;
- _PBLKDESC pdesc2;
- void *retp;
- size_t oldsize;
- size_t currsize;
-
- /* special cases, handling mandated by ANSI
- */
- if ( pblock == NULL )
- /* just do a malloc of newsize bytes and return a pointer to
- * the new block
- */
- return( _malloc_base(newsize) );
-
- if ( newsize == 0 ) {
- /* free the block and return NULL
- */
- _free_base(pblock);
- return( NULL );
- }
-
- /* make newsize a valid allocation block size (i.e., round up to the
- * nearest whole number of dwords)
- */
- newsize = _ROUND2(newsize, _GRANULARITY);
-
-
- /* if multi-thread support enabled, lock the heap here
- */
- _mlock(_HEAP_LOCK);
-
- /* set pdesc to point to the descriptor for *pblock
- */
- pdesc = _BACKPTR(pblock);
-
- if ( _ADDRESS(pdesc) != ((char *)pblock - _HDRSIZE) )
- _heap_abort();
-
- /* see if pblock is big enough already, or can be expanded (in place)
- * to be big enough.
- */
- if ( ((oldsize = currsize = BLKSZ(pdesc, pblock)) > newsize) ||
- (_heap_expand_block(pdesc, &currsize, newsize) == 0) ) {
-
- /* if necessary, mark pdesc as inuse
- */
- if ( _IS_FREE(pdesc) ) {
- _SET_INUSE(pdesc);
- }
-
- /* trim pdesc down to be exactly newsize bytes, if necessary
- */
- if ( (currsize > newsize) &&
- ((pdesc2 = _heap_split_block(pdesc, newsize)) != NULL) )
- {
- _SET_FREE(pdesc2);
- }
-
- retp = pblock;
- goto realloc_done;
- }
-
- /* try malloc-ing a new block of the requested size. if successful,
- * copy over the data from the original block and free it.
- */
- if ( (retp = _malloc_base(newsize)) != NULL ) {
- memcpy(retp, pblock, oldsize);
- _free_base_lk(pblock);
- }
- /* else if unsuccessful, return retp (== NULL) */
-
- realloc_done:
- /* if multi-thread support is enabled, unlock the heap here
- */
- _munlock(_HEAP_LOCK);
-
- return(retp);
- }
-
-
- /***
- *void *_expand(void *pblock, 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. In the case of expansion, if the
- * block cannot be expanded to newsize bytes, it is expanded as much as
- * possible.
- *
- * Special Notes For Multi-thread: The heap is locked just before pdesc
- * is assigned and unlocked immediately prior to the return statement.
- *
- *Entry:
- * void *pblock - 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., pblock)
- * Failure: NULL
- *
- *Uses:
- *
- *Exceptions:
- * If pblock does not point to a valid allocation block in the heap,
- * _expand() will behave unpredictably and probably corrupt the heap.
- *
- *******************************************************************************/
-
- void * __cdecl _expand_base (
- REG1 void *pblock,
- size_t newsize
- )
- {
- REG2 _PBLKDESC pdesc;
- _PBLKDESC pdesc2;
- void *retp;
- size_t oldsize;
- size_t currsize;
- int index;
- #if defined (_M_MPPC) || defined (_M_M68K)
- struct _heap_region_ *pHeapRegions;
- #endif /* defined (_M_MPPC) || defined (_M_M68K) */
-
- /* make newsize a valid allocation block size (i.e., round up to the
- * nearest whole number of dwords)
- */
- newsize = _ROUND2(newsize, _GRANULARITY);
-
-
- retp = pblock;
-
- /* validate size */
- if ( newsize > _HEAP_MAXREQ )
- newsize = _HEAP_MAXREQ;
-
- /* if multi-thread support enabled, lock the heap here
- */
- _mlock(_HEAP_LOCK);
-
- /* set pdesc to point to the descriptor for *pblock
- */
- pdesc = _BACKPTR(pblock);
-
- /* see if pblock is big enough already, or can be expanded (in place)
- * to be big enough.
- */
- if ( ((oldsize = currsize = BLKSZ(pdesc, pblock)) >= newsize) ||
- (_heap_expand_block(pdesc, &currsize, newsize) == 0) ) {
- /* pblock is (now) big enough. trim it down, if necessary
- */
- if ( (currsize > newsize) &&
- ((pdesc2 = _heap_split_block(pdesc, newsize)) != NULL) )
- {
- _SET_FREE(pdesc2);
- currsize = newsize;
- }
- goto expand_done;
- }
-
- /* if the heap block is at the end of a region, attempt to grow the
- * region
- */
- if ( (pdesc->pnextdesc == &_heap_desc.sentinel) ||
- _IS_DUMMY(pdesc->pnextdesc) ) {
-
- /* look up the region index
- */
- #if defined (_M_MPPC) || defined (_M_M68K)
- pHeapRegions = (struct _heap_region_ *)(*hHeapRegions);
- for ( index = 0 ; index < _heap_region_table_cur ; index++ )
- if (((pHeapRegions + index)->_regbase < pblock) &&
- (((char *)((pHeapRegions + index)->_regbase) +
- (pHeapRegions + index)->_currsize) >= (char *)pblock) )
- break;
- #else /* defined (_M_MPPC) || defined (_M_M68K) */
- for ( index = 0 ; index < _HEAP_REGIONMAX ; index++ )
- if ( (_heap_regions[index]._regbase < pblock) &&
- (((char *)(_heap_regions[index]._regbase) +
- _heap_regions[index]._currsize) >=
- (char *)pblock) )
- break;
- #endif /* defined (_M_MPPC) || defined (_M_M68K) */
- /* make sure a valid region index was obtained (pblock could
- * lie in a portion of heap memory donated by a user call to
- * _heapadd(), which therefore would not appear in the region
- * table)
- */
- #if defined (_M_MPPC) || defined (_M_M68K)
- if ( index == _heap_region_table_cur ) {
- #else /* defined (_M_MPPC) || defined (_M_M68K) */
- if ( index == _HEAP_REGIONMAX ) {
- #endif /* defined (_M_MPPC) || defined (_M_M68K) */
- retp = NULL;
- goto expand_done;
- }
-
- /* try growing the region. the difference between newsize and
- * the current size of the block, rounded up to the nearest
- * whole number of pages, is the amount the region needs to
- * be grown. if successful, try expanding the block again
- */
- if ( (_heap_grow_region(index, _ROUND2(newsize - currsize,
- _PAGESIZE_)) == 0) &&
- (_heap_expand_block(pdesc, &currsize, newsize) == 0) )
- {
- /* pblock is (now) big enough. trim it down to be
- * exactly size bytes, if necessary
- */
- if ( (currsize > newsize) && ((pdesc2 =
- _heap_split_block(pdesc, newsize)) != NULL) )
- {
- _SET_FREE(pdesc2);
- currsize = newsize;
- }
- }
- else
- retp = NULL;
- }
- else
- retp = NULL;
-
- expand_done:
- /* if multi-thread support is enabled, unlock the heap here
- */
- _munlock(_HEAP_LOCK);
-
- return(retp);
- }
-
-
- /***
- *int _heap_expand_block(pdesc, pcurrsize, newsize) - expand an allocation block
- * in place (without trying to 'grow' the heap)
- *
- *Purpose:
- *
- *Entry:
- * _PBLKDESC pdesc - pointer to the allocation block descriptor
- * size_t *pcurrsize - pointer to size of the allocation block (i.e.,
- * *pcurrsize == _BLKSIZE(pdesc), on entry)
- * size_t newsize - requested minimum size for the expanded allocation
- * block (i.e., newsize >= _BLKSIZE(pdesc), on exit)
- *
- *Exit:
- * Success: 0
- * Failure: -1
- * In either case, *pcurrsize is updated with the new size of the block
- *
- *Exceptions:
- * It is assumed that pdesc points to a valid allocation block descriptor.
- * It is also assumed that _BLKSIZE(pdesc) == *pcurrsize on entry. If
- * either of these assumptions is violated, _heap_expand_block will almost
- * certainly trash the heap.
- *
- *******************************************************************************/
-
- static int __cdecl _heap_expand_block (
- REG1 _PBLKDESC pdesc,
- REG3 size_t *pcurrsize,
- size_t newsize
- )
- {
- REG2 _PBLKDESC pdesc2;
-
- _ASSERTE(("_heap_expand_block: bad pdesc arg", _CHECK_PDESC(pdesc)));
- _ASSERTE(("_heap_expand_block: bad pcurrsize arg", *pcurrsize == _BLKSIZE(pdesc)));
-
- for ( pdesc2 = pdesc->pnextdesc ; _IS_FREE(pdesc2) ;
- pdesc2 = pdesc->pnextdesc ) {
-
- /* coalesce with pdesc. check for special case of pdesc2
- * being proverdesc.
- */
- pdesc->pnextdesc = pdesc2->pnextdesc;
-
- if ( pdesc2 == _heap_desc.proverdesc )
- _heap_desc.proverdesc = pdesc;
-
- /* update *pcurrsize, place *pdesc2 on the empty descriptor
- * list and see if the coalesced block is now big enough
- */
- *pcurrsize += _MEMSIZE(pdesc2);
-
- _PUTEMPTY(pdesc2)
- }
-
- if ( *pcurrsize >= newsize )
- return(0);
- else
- return(-1);
- }
-
-
- #endif /* WINHEAP */
-