summaryrefslogtreecommitdiff
path: root/dmake/dbug/malloc/free.c
blob: a8fc3ca259b624276defa4b6c02272dc59061c1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * (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);

}