1 /*
2 * gmem.c
3 *
4 * Memory routines with out-of-memory checking.
5 *
6 * Copyright 1996-2003 Glyph & Cog, LLC
7 */
8
9 #include <aconf.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stddef.h>
13 #include <string.h>
14 #include <limits.h>
15 #include "gmem.h"
16
17 #ifdef DEBUG_MEM
18
19 typedef struct _GMemHdr {
20 unsigned int magic;
21 int size;
22 int index;
23 struct _GMemHdr *next, *prev;
24 } GMemHdr;
25
26 #define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7)
27 #define gMemTrlSize (sizeof(long))
28
29 #define gMemMagic 0xabcd9999
30
31 #if gmemTrlSize==8
32 #define gMemDeadVal 0xdeadbeefdeadbeefUL
33 #else
34 #define gMemDeadVal 0xdeadbeefUL
35 #endif
36
37 /* round data size so trailer will be aligned */
38 #define gMemDataSize(size) \
39 ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)
40
41 static GMemHdr *gMemHead = NULL;
42 static GMemHdr *gMemTail = NULL;
43
44 static int gMemIndex = 0;
45 static int gMemAlloc = 0;
46 static int gMemInUse = 0;
47 static int gMaxMemInUse = 0;
48
49 #endif /* DEBUG_MEM */
50
gmalloc(int size)51 void *gmalloc(int size) GMEM_EXCEP {
52 #ifdef DEBUG_MEM
53 int size1;
54 char *mem;
55 GMemHdr *hdr;
56 void *data;
57 unsigned long *trl, *p;
58
59 if (size < 0) {
60 gMemError("Invalid memory allocation size");
61 }
62 if (size == 0) {
63 return NULL;
64 }
65 size1 = gMemDataSize(size);
66 if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) {
67 gMemError("Out of memory");
68 }
69 hdr = (GMemHdr *)mem;
70 data = (void *)(mem + gMemHdrSize);
71 trl = (unsigned long *)(mem + gMemHdrSize + size1);
72 hdr->magic = gMemMagic;
73 hdr->size = size;
74 hdr->index = gMemIndex++;
75 if (gMemTail) {
76 gMemTail->next = hdr;
77 hdr->prev = gMemTail;
78 gMemTail = hdr;
79 } else {
80 hdr->prev = NULL;
81 gMemHead = gMemTail = hdr;
82 }
83 hdr->next = NULL;
84 ++gMemAlloc;
85 gMemInUse += size;
86 if (gMemInUse > gMaxMemInUse) {
87 gMaxMemInUse = gMemInUse;
88 }
89 for (p = (unsigned long *)data; p <= trl; ++p) {
90 *p = gMemDeadVal;
91 }
92 return data;
93 #else
94 void *p;
95
96 if (size < 0) {
97 gMemError("Invalid memory allocation size");
98 }
99 if (size == 0) {
100 return NULL;
101 }
102 if (!(p = malloc(size))) {
103 gMemError("Out of memory");
104 }
105 return p;
106 #endif
107 }
108
grealloc(void * p,int size)109 void *grealloc(void *p, int size) GMEM_EXCEP {
110 #ifdef DEBUG_MEM
111 GMemHdr *hdr;
112 void *q;
113 int oldSize;
114
115 if (size < 0) {
116 gMemError("Invalid memory allocation size");
117 }
118 if (size == 0) {
119 if (p) {
120 gfree(p);
121 }
122 return NULL;
123 }
124 if (p) {
125 hdr = (GMemHdr *)((char *)p - gMemHdrSize);
126 oldSize = hdr->size;
127 q = gmalloc(size);
128 memcpy(q, p, size < oldSize ? size : oldSize);
129 gfree(p);
130 } else {
131 q = gmalloc(size);
132 }
133 return q;
134 #else
135 void *q;
136
137 if (size < 0) {
138 gMemError("Invalid memory allocation size");
139 }
140 if (size == 0) {
141 if (p) {
142 free(p);
143 }
144 return NULL;
145 }
146 if (p) {
147 q = realloc(p, size);
148 } else {
149 q = malloc(size);
150 }
151 if (!q) {
152 gMemError("Out of memory");
153 }
154 return q;
155 #endif
156 }
157
gmallocn(int nObjs,int objSize)158 void *gmallocn(int nObjs, int objSize) GMEM_EXCEP {
159 int n;
160
161 if (nObjs == 0) {
162 return NULL;
163 }
164 n = nObjs * objSize;
165 if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
166 gMemError("Bogus memory allocation size");
167 }
168 return gmalloc(n);
169 }
170
greallocn(void * p,int nObjs,int objSize)171 void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP {
172 int n;
173
174 if (nObjs == 0) {
175 if (p) {
176 gfree(p);
177 }
178 return NULL;
179 }
180 n = nObjs * objSize;
181 if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
182 gMemError("Bogus memory allocation size");
183 }
184 return grealloc(p, n);
185 }
186
gfree(void * p)187 void gfree(void *p) {
188 #ifdef DEBUG_MEM
189 int size;
190 GMemHdr *hdr;
191 unsigned long *trl, *clr;
192
193 if (p) {
194 hdr = (GMemHdr *)((char *)p - gMemHdrSize);
195 if (hdr->magic == gMemMagic &&
196 ((hdr->prev == NULL) == (hdr == gMemHead)) &&
197 ((hdr->next == NULL) == (hdr == gMemTail))) {
198 if (hdr->prev) {
199 hdr->prev->next = hdr->next;
200 } else {
201 gMemHead = hdr->next;
202 }
203 if (hdr->next) {
204 hdr->next->prev = hdr->prev;
205 } else {
206 gMemTail = hdr->prev;
207 }
208 --gMemAlloc;
209 gMemInUse -= hdr->size;
210 size = gMemDataSize(hdr->size);
211 trl = (unsigned long *)((char *)hdr + gMemHdrSize + size);
212 if (*trl != gMemDeadVal) {
213 fprintf(stderr, "Overwrite past end of block %d at address %p\n",
214 hdr->index, p);
215 }
216 for (clr = (unsigned long *)hdr; clr <= trl; ++clr) {
217 *clr = gMemDeadVal;
218 }
219 free(hdr);
220 } else {
221 fprintf(stderr, "Attempted to free bad address %p\n", p);
222 }
223 }
224 #else
225 if (p) {
226 free(p);
227 }
228 #endif
229 }
230
gMemError(const char * msg)231 void gMemError(const char *msg) GMEM_EXCEP {
232 #if USE_EXCEPTIONS
233 throw GMemException();
234 #else
235 fprintf(stderr, "%s\n", msg);
236 exit(1);
237 #endif
238 }
239
240 #ifdef DEBUG_MEM
gMemReport(FILE * f)241 void gMemReport(FILE *f) {
242 GMemHdr *p;
243
244 fprintf(f, "%d memory allocations in all\n", gMemIndex);
245 fprintf(f, "maximum memory in use: %d bytes\n", gMaxMemInUse);
246 if (gMemAlloc > 0) {
247 fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc);
248 fprintf(f, " index size\n");
249 fprintf(f, "-------- --------\n");
250 for (p = gMemHead; p; p = p->next) {
251 fprintf(f, "%8d %8d\n", p->index, p->size);
252 }
253 } else {
254 fprintf(f, "No memory blocks left allocated\n");
255 }
256 }
257 #endif
258
copyString(const char * s)259 char *copyString(const char *s) {
260 char *s1;
261
262 s1 = (char *)gmalloc((int)strlen(s) + 1);
263 strcpy(s1, s);
264 return s1;
265 }
266