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