summaryrefslogtreecommitdiffstats
path: root/private/windows/diamond/mem.c
blob: bad8f02bf8160f5be3352c99d610e1fb81924c7f (plain) (blame)
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/***    mem.c - Memory Manager
 *
 *      Microsoft Confidential
 *      Copyright (C) Microsoft Corporation 1993-1994
 *      All Rights Reserved.
 *
 *  Author:
 *      Benjamin W. Slivka
 *
 *  History:
 *      10-Aug-1993 bens    Initial version
 *      11-Aug-1993 bens    Lift code from STOCK.EXE win app
 *      12-Aug-1993 bens    Get strings from memory.msg
 *      01-Sep-1993 bens    Add NULL pointer checks to MMAssert and MMStrDup
 *      18-Mar-1994 bens    Make sure non-assert build works; rename
 *      18-May-1994 bens    Allow turning off MemCheckHeap() in debug build
 *                              (it can really, really slow things down!)
 *
 *  Functions:
 *      MemAlloc  - Allocate memory block
 *      MemFree   - Free memory block
 *      MemStrDup - Duplicate string to new memory block
 *
 *  Functions available in ASSERT build:
 *      MemAssert       - Assert that pointer was allocated by MemAlloc
 *      MemCheckHeap    - Check entire memory heap
 *      MemGetSize      - Return allocated size of memory block
 *      MemSetCheckHeap - Control whether MemCheckHeap is done on every
 *                          every MemAlloc and MemFree!
 */

#include <string.h>  
#include <memory.h>
#include <malloc.h>

#include "types.h"
#include "asrt.h"

#ifdef ASSERT   // Must be after asrt.h!

#include "mem.h"
#include "mem.msg"


/***    MEMSIG - memory signature
 *
 *  This is placed at the front and end of every dynamic memory
 *  alloction in DEBUG builds.  The pointer has to be unaligned for
 *  RISC machines.
 */
typedef ULONG MEMSIG;    /* ms - memory signature */
typedef MEMSIG UNALIGNED *PMEMSIG; /* pms */

#define msHEAD  0x12345678L     // Head signature
#define msTAIL  0x87654321L     // Tail signature
#define msBAD   0L              // Bad signature
#define cmsTAIL 2               // Number of tail signatures


typedef struct mh_t {
    MEMSIG       ms;            // Head signature (msHEAD)
    unsigned     cb;            // Size of user block
    struct mh_t *pmhNext;       // Next block
    struct mh_t *pmhPrev;       // Previous block
    // char      ach[?];        // User block; length is cb
    // MEMSIG    ms[cmsTAIL];   // Tail signature area (msTAIL...)
} MEMHDR;   /* mh - memory header */
typedef MEMHDR *PMEMHDR; /* pmh */


#define PMHFromPV(pv)  ((PMEMHDR)((char *)pv - sizeof(MEMHDR)))
#define PVFromPMH(pmh) ((void *)((char *)pmh+sizeof(MEMHDR)))


STATIC PMEMHDR pmhList=NULL;    // List of memory blocks
STATIC BOOL    fDoCheckHeap=TRUE; // TRUE => check heap regularly


void MemSetCheckHeap(BOOL f)
{
    fDoCheckHeap = f;
}


void MMCheckHeap(char *pszFile, int iLine)
{
    PMEMHDR pmh;

    for (pmh = pmhList; pmh != NULL; pmh = pmh->pmhNext)
        MMAssert(PVFromPMH(pmh),pszFile,iLine);
}


void MMAssert(void *pv, char *pszFile, int iLine)
{
    int       i;
    PMEMHDR   pmh;
    PMEMSIG   pms;

    AssertSub(pv!=NULL,pszFile,iLine);
    pmh = PMHFromPV(pv);
    if ((void *)pmh > pv) {                     // Pointer wrapped
        AssertForce(pszMEMERR_NULL_POINTER,pszFile,iLine);
    }

    // Test head signature
    if (pmh->ms != msHEAD) {
        AssertForce(pszMEMERR_BAD_HEAD_SIG,pszFile,iLine);
    }

    // Test tail signatures
    pms = (PMEMSIG)( (char *)pmh + sizeof(MEMHDR) + pmh->cb );
    for (i=0; i<cmsTAIL; i++) {
        if (*pms++ != msTAIL) {
            AssertForce(pszMEMERR_BAD_HEAD_SIG,pszFile,iLine);
        }
    }
} /* MMAssert */


void MMFree(void *pv, char *pszFile, int iLine)
{
    PMEMHDR pmh;

    MMAssert(pv,pszFile,iLine);

    //** Check heap if enabled
    if (fDoCheckHeap) {
        MMCheckHeap(pszFile,iLine);
    }

    pmh = PMHFromPV(pv);

    // Make previous block point to next block
    if (pmh->pmhPrev != NULL) {         // pmh is not at front of list
        // before: a->p->?
        pmh->pmhPrev->pmhNext = pmh->pmhNext;
        // after:  a->?
    }
    else {                              // pmh is at front of list
        // before: list->p->?
        pmhList = pmh->pmhNext;
        // after: list->?
    }

    // Make next block point to previous block
    if (pmh->pmhNext != NULL) {         // pmh is not at end of list
        // before: ?<-p<->a
        pmh->pmhNext->pmhPrev = pmh->pmhPrev;
        // after:  ?<-a
    }

    // Obliterate signature
    pmh->ms = msBAD;

    // Free memory
    free((char *)pmh);
}


void *MMAlloc(unsigned cb, char *pszFile, int iLine)
{
    unsigned    cbAlloc;
    int         i;
    PMEMHDR     pmh;
    PMEMSIG     pms;

    if (fDoCheckHeap) {
        MMCheckHeap(pszFile,iLine);
    }

	// Solves alignment problems on the RISCs
	cb = (cb+3) & ~3;

    cbAlloc = cb+sizeof(MEMHDR)+sizeof(MEMSIG)*cmsTAIL;
    pmh = malloc(cbAlloc);
    if (pmh != NULL) {
        pmh->ms = msHEAD;           // Store head signature
        pmh->cb = cb;               // Store size of user block

        // Add block to front of list (Easiest code!)
        if (pmhList != NULL) {      // List is not empty
            pmhList->pmhPrev = pmh; // Point old top block back at us
        }
        pmh->pmhNext = pmhList;     // Next element is old top block
        pmh->pmhPrev = NULL;        // We are first, so no prev block
        pmhList = pmh;              // Make ourselves first

        // Fill in tail signatures
        pms = (PMEMSIG)( (char *)pmh + sizeof(MEMHDR) + pmh->cb );
        for (i=0; i<cmsTAIL; i++) {
            *pms++ = msTAIL;
        }
        return PVFromPMH(pmh);
    }
    else {
        AssertForce(pszMEMERR_OUT_OF_MEMORY,pszFile,iLine);
/*
        printf("panic: out of memory in MMAlloc\n");
            printf("\n");
            printf("Dump of heap (newest alloc to oldest)\n");
            printf("\n");
            printf("Size  Addr Content\n");
            printf("----- ---- -------\n");
            for (pmh = pmhList; pmh != NULL; pmh = pmh->pmhNext) {
                pch = PVFromPMH(pmh);
            printf("%5d %04x %s\n",pmh->cb,(unsigned)pch,pch);
        }
        return NULL;
*/
    }
}


char *MMStrDup(char *pch, char *pszFile, int iLine)
{
    unsigned    cb;
    char       *pchDst;

    //** Make sure pointer is not null.
    //   NOTE: pch does not have to be a string we dynamically allocated!
    AssertSub(pch!=NULL,pszFile,iLine);

    cb = strlen(pch)+1;                 // Count NUL terminator
    pchDst = MMAlloc(cb,pszFile,iLine); // Alloc new copy
    if (pchDst != NULL) {               // Success
        memcpy(pchDst,pch,cb);          // Copy string
    }
    return pchDst;                      // Return string copy
}


int  MemGetSize(void *pv)
{
    PMEMHDR pmh;

    MMAssert(pv,__FILE__,__LINE__);

    pmh = PMHFromPV(pv);
    return pmh->cb;
}
#endif // !ASSERT