Background: We use vs2005 as the environment. The installation directory is C:/program files/Microsoft Visual Studio 8, which is called C: the/program files/Microsoft Visual Studio 8/VC/directory is the VC directory, and the C:/program files/Microsoft Visual Studio 8/VC/CRT directory is the runtime directory, the following directory contains the C Runtime Library source code C:/program files/Microsoft Visual Studio 8/VC/CRT/src.
(The Code is based on the C Runtime Library of vs2005. The other versions are slightly different)
Assume the following statement: char * P = (char *) malloc (4); malloc finally calls heap_alloc_dbg in dbgheap. C.
Size_t blocksize; <br/> int fignore = false; <br/> _ crtmemblockheader * phead;
We will focus on these three variables.
If (_ pfnallochook )&&! (* _ Pfnallochook) (_ hook_alloc, null, nsize, nblockuse, lrequest, (const unsigned char *) szfilename, nline) <br/>
Define _ pfnallochook in dbghook. C, which is a hook function pointer for memory application. The default value is _ crtdefaultallochook. If the default function does nothing, 1 is returned directly. We can call the _ crtsetallochook function to set our own function. In this way, our function will be called back once before each memory allocation. The above is the place where the function is called in the allocation interface.
/* Cannot ignore CRT allocations */<br/> If (_ block_type (nblockuse )! = _ Crt_block & <br/>! (_ Crtdbgflag & _ crtdbg_alloc_mem_df) <br/> fignore = true;
If the _ crtdbg_alloc_mem_df bit of _ crtdbgflag is not set, the debugging information is ignored.
Blocksize = sizeof (_ crtmemblockheader) + nsize + nnomanslandsize; <br/> phead = (_ crtmemblockheader *) _ heap_alloc_base (blocksize );
The heapalloc memory is called in _ heap_alloc_base. The requested size is not the nsize we requested, but nsize + sizeof (_ crtmemblockheader) + nnomanslandsize. That is to say, every time we apply for a piece of memory, additional memory will be allocated. The _ crtmemblockheader is used to maintain a linked list, and each node of the linked list is an application, nnomanslandsize is generally a four-byte area.
If (_ pfirstblock) <br/> _ pfirstblock-> pblockheaderprev = phead; <br/> else <br/> _ plastblock = phead; </P> <p> phead-> pblockheadernext = _ pfirstblock; <br/> phead-> pblockheaderprev = NULL; <br/> phead-> szfilename = (char *) szfilename; <br/> phead-> nline = nline; <br/> phead-> ndatasize = nsize; <br/> phead-> nblockuse = nblockuse; <br/> phead-> lrequest = lrequest; </P> <p>/* link blocks together */<br/> _ pfirstblock = phead;
Obviously, insert the new node into the table header of the linked list, and point _ pfirstblock to the table header. The pfirstblock global variable is defined in dbgheap. C.
Let's look at the relationship diagram.
Since the end of _ crtmemblockheader, that is, the data header, there is also an nnomanslandsize region gap (as can be seen from the definition of _ crtmemblockheader ). The function returns pbdata (phead), which is the first address of data. This is the memory that we can actually operate on, and the memory is enclosed by the gap of nnomanslandsize.
/* Fill in gap before and after real block */<br/> memset (void *) phead-> GaP, _ bnomanslandfill, nnomanslandsize ); <br/> memset (void *) (pbdata (phead) + nsize), _ bnomanslandfill, nnomanslandsize );
These two locations are initialized to _ bnomanslandfill, Which is 0xfd. It is used to determine whether the user has crossed the border when operating the address.
Memset (void *) pbdata (phead), _ bcleanlandfill, nsize );
The actual user space data is initialized to _ bcleanlandfill, Which is 0xcd. (You can test and apply for a space to see if it is all 0xcd .)
_ The pfirstblock header is not open to users. To obtain this header pointer and traverse the entire table, you can apply for a memory of any size (usually 1 ), this memory is placed in the header, and the obtained address is shifted to one _ crtmemblockheader to get the current header pointer. In this way, the address of the second node is obtained, and the address of the second node is recorded, then release the allocated memory, which is the second node and becomes the header.
Void * P = malloc (1 );
_ Crtmemblockheader * pheader = (_ crtmemblockheader *) P)-1)-> pblockheadernext;
Delete P;