home *** CD-ROM | disk | FTP | other *** search
- /***
- *malloc.c - Get a block of memory from the heap
- *
- * Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
- *
- *Purpose:
- * Defines the malloc() function.
- *
- *******************************************************************************/
-
- #include <cruntime.h>
- #include <malloc.h>
- #include <internal.h>
- #include <mtdll.h>
- #include <dbgint.h>
-
- #ifdef WINHEAP
- #include <windows.h>
- #include <winheap.h>
- #else /* WINHEAP */
- #include <heap.h>
- #endif /* WINHEAP */
-
-
- extern int _newmode; /* malloc new() handler mode */
-
-
- /***
- *void *malloc(size_t size) - Get a block of memory from the heap
- *
- *Purpose:
- * Allocate of block of memory of at least size bytes from the heap and
- * return a pointer to it.
- *
- * Calls the new appropriate new handler (if installed).
- *
- *Entry:
- * size_t size - size of block requested
- *
- *Exit:
- * Success: Pointer to memory block
- * Failure: NULL (or some error value)
- *
- *Uses:
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void * __cdecl _malloc_base (size_t size)
-
- {
- return _nh_malloc_base(size, _newmode);
- }
-
-
- /***
- *void *_nh_malloc_base(size_t size) - Get a block of memory from the heap
- *
- *Purpose:
- * Allocate of block of memory of at least size bytes from the heap and
- * return a pointer to it.
- *
- * Calls the appropriate new handler (if installed).
- *
- * There are two distinct new handler schemes supported. The 'new' ANSI
- * C++ scheme overrides the 'old' scheme when it is activated. A value of
- * _NOPTH for the 'new' handler indicates that it is inactivated and the
- * 'old' handler is then called.
- *
- *Entry:
- * size_t size - size of block requested
- *
- *Exit:
- * Success: Pointer to memory block
- * Failure: NULL (or some error value)
- *
- *Uses:
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void * __cdecl _nh_malloc_base (size_t size, int nhFlag)
- {
- void * pvReturn;
-
- // validate size
- if (size > _HEAP_MAXREQ)
- return NULL;
-
- #ifndef WINHEAP
- /* round requested size */
- size = _ROUND2(size, _GRANULARITY);
- #endif /* WINHEAP */
-
- for (;;) {
-
- // allocate memory block
- if (size <= _HEAP_MAXREQ)
- pvReturn = _heap_alloc_base(size);
- else
- pvReturn = NULL;
-
- // if successful allocation, return pointer to memory
- // if new handling turned off altogether, return NULL
-
- if (pvReturn || nhFlag == 0)
- return pvReturn;
-
- // call installed new handler
- if (!_callnewh(size))
- return NULL;
-
- // new handler was successful -- try to allocate again
- }
- }
-
- /***
- *void *_heap_alloc_base(size_t size) - does actual allocation
- *
- *Purpose:
- * Same as malloc() except the new handler is not called.
- *
- *Entry:
- * See malloc
- *
- *Exit:
- * See malloc
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void * __cdecl _heap_alloc_base (size_t size)
-
- {
- #ifdef WINHEAP
- void * pvReturn;
- #else /* WINHEAP */
- _PBLKDESC pdesc;
- _PBLKDESC pdesc2;
- #endif /* WINHEAP */
-
-
- #ifdef WINHEAP
-
- if (size <= __sbh_threshold)
- {
- _mlock(_HEAP_LOCK);
- pvReturn = __sbh_alloc_block(size);
- _munlock(_HEAP_LOCK);
- if (pvReturn)
- return pvReturn;
- }
-
- if (size == 0)
- size = 1;
- size = (size + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1);
- return HeapAlloc(_crtheap, 0, size);
- }
-
- #else /* WINHEAP */
-
- /* try to find a big enough free block
- */
- if ( (pdesc = _heap_search(size)) == NULL )
- {
- if ( _heap_grow(size) != -1 )
- {
- /* try finding a big enough free block again. the
- * success of the call to _heap_grow should guarantee
- * it, but...
- */
- if ( (pdesc = _heap_search(size)) == NULL )
- {
- /* something unexpected, and very bad, has
- * happened. abort!
- */
- _heap_abort();
- }
- }
- else
- return NULL;
- }
-
- /* carve the block into two pieces (if necessary). the first piece
- * shall be of the exact requested size, marked inuse and returned to
- * the caller. the leftover piece is to be marked free.
- */
- if ( _BLKSIZE(pdesc) != size ) {
- /* split up the block and free the leftover piece back to
- * the heap
- */
- if ( (pdesc2 = _heap_split_block(pdesc, size)) != NULL )
- _SET_FREE(pdesc2);
- }
-
- /* mark pdesc inuse
- */
- _SET_INUSE(pdesc);
-
- /* check proverdesc and reset, if necessary
- */
-
- _heap_desc.proverdesc = pdesc->pnextdesc;
-
- return( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) );
- }
-
-
- /***
- *_PBLKDESC _heap_split_block(pdesc, newsize) - split a heap allocation block
- * into two allocation blocks
- *
- *Purpose:
- * Split the allocation block described by pdesc into two blocks, the
- * first one being of newsize bytes.
- *
- * Notes: It is caller's responsibilty to set the status (i.e., free
- * or inuse) of the two new blocks, and to check and reset proverdesc
- * if necessary. See Exceptions (below) for additional requirements.
- *
- *Entry:
- * _PBLKDESC pdesc - pointer to the allocation block descriptor
- * size_t newsize - size for the first of the two sub-blocks (i.e.,
- * (i.e., newsize == _BLKSIZE(pdesc), on exit)
- *
- *Exit:
- * If successful, return a pointer to the descriptor for the leftover
- * block.
- * Otherwise, return NULL.
- *
- *Exceptions:
- * It is assumed pdesc points to a valid allocation block descriptor and
- * newsize is a valid heap block size as is (i.e., WITHOUT rounding). If
- * either of these of assumption is violated, _heap_split_block() will
- * likely corrupt the heap. Note also that _heap_split_block will simply
- * return to the caller if newsize >= _BLKSIZE(pdesc), on entry.
- *
- *******************************************************************************/
-
- _PBLKDESC __cdecl _heap_split_block (
- REG1 _PBLKDESC pdesc,
- size_t newsize
- )
- {
- REG2 _PBLKDESC pdesc2;
-
- _ASSERTE(("_heap_split_block: bad pdesc arg", _CHECK_PDESC(pdesc)));
- _ASSERTE(("_heap_split_block: bad newsize arg", _ROUND2(newsize,_GRANULARITY) == newsize));
-
- /* carve the block into two pieces (if possible). the first piece
- * is to be exactly newsize bytes.
- */
- if ( (_BLKSIZE(pdesc) > newsize) && ((pdesc2 = __getempty())
- != NULL) )
- {
- /* set it up to manage the second piece and link it in to
- * the list
- */
- pdesc2->pblock = (void *)((char *)_ADDRESS(pdesc) + newsize +
- _HDRSIZE);
- *(void **)(pdesc2->pblock) = pdesc2;
- pdesc2->pnextdesc = pdesc->pnextdesc;
- pdesc->pnextdesc = pdesc2;
-
- return pdesc2;
- }
- return NULL;
- }
-
- #endif /* WINHEAP */
-
-