/*
 * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
 * You may copy, distribute, and use this software as long as this
 * copyright statement is not removed.
 */
#include <stdio.h>
#include "malloc.h"
#include "debug.h"

/*
 * Function:	free()
 *
 * Purpose:	to deallocate malloced data
 *
 * Arguments:	ptr	- pointer to data area to deallocate
 *
 * Returns:	nothing of any value
 *
 * Narrative:
 *		verify pointer is within malloc region
 *		get mlist pointer from passed address
 *		verify magic number
 *		verify inuse flag
 *		verify pointer connections with surrounding segments
 *		turn off inuse flag
 *		verify no data overrun into non-malloced area at end of segment
 *		IF possible join segment with next segment
 *		IF possible join segment with previous segment
 *		Clear all data in segment (to make sure it isn't reused)
 *
 */
#ifndef lint
static
char rcs_hdr[] = "$Id: free.c,v 1.2 2006/07/25 10:07:53 rt Exp $";
#endif

void
free(cptr)
	char	* cptr;
{
	char			* func = "free";
	int			  i;
	extern int		  malloc_checking;
	extern struct mlist	* malloc_end;
	extern int		  malloc_errno;
	extern char		* malloc_data_end;
	extern char		* malloc_data_start;
	void			  malloc_join();
	void			  malloc_memset();
	struct mlist		* oldptr;
	struct mlist		* ptr;

	/*
	 * IF malloc chain checking is on, go do it.
	 */
	if( malloc_checking )
	{
		(void) malloc_chain_check(1);
	}

	/*
	 * verify that cptr is within the malloc region...
	 */
	if( cptr < malloc_data_start || cptr > malloc_data_end )
	{
		malloc_errno = M_CODE_BAD_PTR;
		malloc_warning(func);
		return;
	}

	/* 
	 * convert pointer to mlist struct pointer.  To do this we must 
	 * move the pointer backwards the correct number of bytes...
	 */
	
	ptr = (struct mlist *) (cptr - M_SIZE);
	
	if( (ptr->flag&M_MAGIC) != M_MAGIC )
	{
		malloc_errno = M_CODE_BAD_MAGIC;
		malloc_warning(func);
		return;
	}

	if( ! (ptr->flag & M_INUSE) )
	{
		malloc_errno = M_CODE_NOT_INUSE;
		malloc_warning(func);
		return;
	}

 	if( (ptr->prev && (ptr->prev->next != ptr) ) ||
	    (ptr->next && (ptr->next->prev != ptr) ) ||
	    ((ptr->next == NULL) && (ptr->prev == NULL)) )
	{
		malloc_errno = M_CODE_BAD_CONNECT;
		malloc_warning(func);
		return;
	}

	ptr->flag &= ~M_INUSE;

	/*
	 * verify that the user did not overrun the requested number of bytes.
	 */
	for(i=ptr->r_size; i < ptr->s.size; i++)
	{
		if( ptr->data[i] != M_FILL )
		{
			malloc_errno = M_CODE_OVERRUN;
			malloc_warning(func);
			break;
		}
	}

	DEBUG3(10,"pointers: prev: 0x%.7x,  ptr: 0x%.7x, next: 0x%.7x",
			ptr->prev, ptr, ptr->next);
	
	DEBUG3(10,"size:     prev: %9d,  ptr: %9d, next: %9d",
			ptr->prev->s.size, ptr->s.size, ptr->next->s.size);
	
	DEBUG3(10,"flags:    prev: 0x%.7x,  ptr: 0x%.7x, next: 0x%.7x",
			ptr->prev->flag, ptr->flag, ptr->next->flag);
	
	/*
	 * check to see if this block can be combined with the next and/or
	 * previous block.  Since it may be joined with the previous block
	 * we will save a pointer to the previous block and test to verify
	 * if it is joined (it's next ptr will no longer point to ptr).
 	 */
	malloc_join(ptr,ptr->next,0,0);
	
	oldptr = ptr->prev;

	malloc_join(ptr->prev, ptr,0,0);

	if( oldptr->next != ptr )
	{
		DEBUG0(10,"Oldptr was changed");
		ptr = oldptr;
	}
	
	/*
	 * fill this block with '\02's to ensure that nobody is using a 
	 * pointer to already freed data...
	 */
	malloc_memset(ptr->data,M_FREE_FILL,(int)ptr->s.size);

}



syntax highlighted by Code2HTML, v. 0.9.1