/src/xpdf-4.04/goo/gmem.cc
Line | Count | Source (jump to first uncovered line) |
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 | | // older compilers won't define SIZE_MAX in stdint.h without this |
14 | | #ifndef __STDC_LIMIT_MACROS |
15 | | # define __STDC_LIMIT_MACROS 1 |
16 | | #endif |
17 | | #include <stdint.h> |
18 | | #include <string.h> |
19 | | #include <limits.h> |
20 | | #if MULTITHREADED && defined(_WIN32) |
21 | | # include <windows.h> |
22 | | #endif |
23 | | #include "gmem.h" |
24 | | |
25 | | #ifdef DEBUG_MEM |
26 | | |
27 | | typedef struct _GMemHdr { |
28 | | unsigned int magic; |
29 | | int index; |
30 | | size_t size; |
31 | | struct _GMemHdr *next, *prev; |
32 | | } GMemHdr; |
33 | | |
34 | | #define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7) |
35 | | #define gMemTrlSize (sizeof(long)) |
36 | | |
37 | | #define gMemMagic 0xabcd9999 |
38 | | |
39 | | #if ULONG_MAX > 0xffffffffL |
40 | | #define gMemDeadVal 0xdeadbeefdeadbeefUL |
41 | | #else |
42 | | #define gMemDeadVal 0xdeadbeefUL |
43 | | #endif |
44 | | |
45 | | /* round data size so trailer will be aligned */ |
46 | | #define gMemDataSize(size) \ |
47 | | (int)(((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)) |
48 | | |
49 | | #define gMemDataSize64(size) \ |
50 | | (size_t)(((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)) |
51 | | |
52 | | static GMemHdr *gMemHead = NULL; |
53 | | static GMemHdr *gMemTail = NULL; |
54 | | |
55 | | static int gMemIndex = 0; |
56 | | static int gMemAlloc = 0; |
57 | | static size_t gMemInUse = 0; |
58 | | static size_t gMaxMemInUse = 0; |
59 | | |
60 | | #if MULTITHREADED |
61 | | # ifdef _WIN32 |
62 | | static CRITICAL_SECTION gMemMutex; |
63 | | static INIT_ONCE gMemMutexInitStruct = INIT_ONCE_STATIC_INIT; |
64 | | static BOOL CALLBACK gMemMutexInitFunc(PINIT_ONCE initOnce, PVOID param, |
65 | | PVOID *context) { |
66 | | InitializeCriticalSection(&gMemMutex); |
67 | | return TRUE; |
68 | | } |
69 | | # define gMemInitMutex InitOnceExecuteOnce(&gMemMutexInitStruct, \ |
70 | | &gMemMutexInitFunc, NULL, NULL) |
71 | | # define gMemLock EnterCriticalSection(&gMemMutex); |
72 | | # define gMemUnlock LeaveCriticalSection(&gMemMutex); |
73 | | # else |
74 | | # include <pthread.h> |
75 | | static pthread_mutex_t gMemMutex = PTHREAD_MUTEX_INITIALIZER; |
76 | | # define gMemInitMutex |
77 | | # define gMemLock pthread_mutex_lock(&gMemMutex) |
78 | | # define gMemUnlock pthread_mutex_unlock(&gMemMutex) |
79 | | # endif |
80 | | #else |
81 | | # define gMemInitMutex |
82 | | # define gMemLock |
83 | | # define gMemUnlock |
84 | | #endif |
85 | | |
86 | | #endif /* DEBUG_MEM */ |
87 | | |
88 | | #ifdef DEBUG_MEM |
89 | | void *gmalloc(int size, int ignore) GMEM_EXCEP { |
90 | | int size1; |
91 | | char *mem; |
92 | | GMemHdr *hdr; |
93 | | void *data; |
94 | | unsigned long *trl, *p; |
95 | | |
96 | | gMemInitMutex; |
97 | | if (size < 0) { |
98 | | gMemError("Invalid memory allocation size"); |
99 | | } |
100 | | if (size == 0) { |
101 | | return NULL; |
102 | | } |
103 | | size1 = gMemDataSize(size); |
104 | | if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) { |
105 | | gMemError("Out of memory"); |
106 | | } |
107 | | hdr = (GMemHdr *)mem; |
108 | | data = (void *)(mem + gMemHdrSize); |
109 | | trl = (unsigned long *)(mem + gMemHdrSize + size1); |
110 | | hdr->magic = gMemMagic; |
111 | | hdr->size = size; |
112 | | gMemLock; |
113 | | if (ignore) { |
114 | | hdr->index = -1; |
115 | | } else { |
116 | | hdr->index = gMemIndex++; |
117 | | } |
118 | | if (gMemTail) { |
119 | | gMemTail->next = hdr; |
120 | | hdr->prev = gMemTail; |
121 | | gMemTail = hdr; |
122 | | } else { |
123 | | hdr->prev = NULL; |
124 | | gMemHead = gMemTail = hdr; |
125 | | } |
126 | | hdr->next = NULL; |
127 | | ++gMemAlloc; |
128 | | gMemInUse += size; |
129 | | if (gMemInUse > gMaxMemInUse) { |
130 | | gMaxMemInUse = gMemInUse; |
131 | | } |
132 | | gMemUnlock; |
133 | | for (p = (unsigned long *)data; p <= trl; ++p) { |
134 | | *p = gMemDeadVal; |
135 | | } |
136 | | return data; |
137 | | } |
138 | | #else |
139 | 1.19M | void *gmalloc(int size) GMEM_EXCEP { |
140 | 1.19M | void *p; |
141 | | |
142 | 1.19M | if (size < 0) { |
143 | 0 | gMemError("Invalid memory allocation size"); |
144 | 0 | } |
145 | 1.19M | if (size == 0) { |
146 | 0 | return NULL; |
147 | 0 | } |
148 | 1.19M | if (!(p = malloc(size))) { |
149 | 0 | gMemError("Out of memory"); |
150 | 0 | } |
151 | 1.19M | return p; |
152 | 1.19M | } |
153 | | #endif |
154 | | |
155 | 0 | void *grealloc(void *p, int size) GMEM_EXCEP { |
156 | | #ifdef DEBUG_MEM |
157 | | GMemHdr *hdr; |
158 | | void *q; |
159 | | int oldSize; |
160 | | |
161 | | if (size < 0) { |
162 | | gMemError("Invalid memory allocation size"); |
163 | | } |
164 | | if (size == 0) { |
165 | | if (p) { |
166 | | gfree(p); |
167 | | } |
168 | | return NULL; |
169 | | } |
170 | | if (p) { |
171 | | hdr = (GMemHdr *)((char *)p - gMemHdrSize); |
172 | | oldSize = (int)hdr->size; |
173 | | q = gmalloc(size); |
174 | | memcpy(q, p, size < oldSize ? size : oldSize); |
175 | | gfree(p); |
176 | | } else { |
177 | | q = gmalloc(size); |
178 | | } |
179 | | return q; |
180 | | #else |
181 | 0 | void *q; |
182 | |
|
183 | 0 | if (size < 0) { |
184 | 0 | gMemError("Invalid memory allocation size"); |
185 | 0 | } |
186 | 0 | if (size == 0) { |
187 | 0 | if (p) { |
188 | 0 | free(p); |
189 | 0 | } |
190 | 0 | return NULL; |
191 | 0 | } |
192 | 0 | if (p) { |
193 | 0 | q = realloc(p, size); |
194 | 0 | } else { |
195 | 0 | q = malloc(size); |
196 | 0 | } |
197 | 0 | if (!q) { |
198 | 0 | gMemError("Out of memory"); |
199 | 0 | } |
200 | 0 | return q; |
201 | 0 | #endif |
202 | 0 | } |
203 | | |
204 | 1.19M | void *gmallocn(int nObjs, int objSize) GMEM_EXCEP { |
205 | 1.19M | int n; |
206 | | |
207 | 1.19M | if (nObjs == 0) { |
208 | 0 | return NULL; |
209 | 0 | } |
210 | 1.19M | n = nObjs * objSize; |
211 | 1.19M | if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { |
212 | 0 | gMemError("Bogus memory allocation size"); |
213 | 0 | } |
214 | 1.19M | return gmalloc(n); |
215 | 1.19M | } |
216 | | |
217 | | #ifdef DEBUG_MEM |
218 | | void *gmalloc64(size_t size, int ignore) GMEM_EXCEP { |
219 | | size_t size1; |
220 | | char *mem; |
221 | | GMemHdr *hdr; |
222 | | void *data; |
223 | | unsigned long *trl, *p; |
224 | | |
225 | | gMemInitMutex; |
226 | | if (size == 0) { |
227 | | return NULL; |
228 | | } |
229 | | size1 = gMemDataSize64(size); |
230 | | if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) { |
231 | | gMemError("Out of memory"); |
232 | | } |
233 | | hdr = (GMemHdr *)mem; |
234 | | data = (void *)(mem + gMemHdrSize); |
235 | | trl = (unsigned long *)(mem + gMemHdrSize + size1); |
236 | | hdr->magic = gMemMagic; |
237 | | hdr->size = size; |
238 | | gMemLock; |
239 | | if (ignore) { |
240 | | hdr->index = -1; |
241 | | } else { |
242 | | hdr->index = gMemIndex++; |
243 | | } |
244 | | if (gMemTail) { |
245 | | gMemTail->next = hdr; |
246 | | hdr->prev = gMemTail; |
247 | | gMemTail = hdr; |
248 | | } else { |
249 | | hdr->prev = NULL; |
250 | | gMemHead = gMemTail = hdr; |
251 | | } |
252 | | hdr->next = NULL; |
253 | | ++gMemAlloc; |
254 | | gMemInUse += size; |
255 | | if (gMemInUse > gMaxMemInUse) { |
256 | | gMaxMemInUse = gMemInUse; |
257 | | } |
258 | | gMemUnlock; |
259 | | for (p = (unsigned long *)data; p <= trl; ++p) { |
260 | | *p = gMemDeadVal; |
261 | | } |
262 | | return data; |
263 | | } |
264 | | #else |
265 | 0 | void *gmalloc64(size_t size) GMEM_EXCEP { |
266 | 0 | void *p; |
267 | |
|
268 | 0 | if (size == 0) { |
269 | 0 | return NULL; |
270 | 0 | } |
271 | 0 | if (!(p = malloc(size))) { |
272 | 0 | gMemError("Out of memory"); |
273 | 0 | } |
274 | 0 | return p; |
275 | 0 | } |
276 | | #endif |
277 | | |
278 | 0 | void *gmallocn64(int nObjs, size_t objSize) GMEM_EXCEP { |
279 | 0 | size_t n; |
280 | |
|
281 | 0 | if (nObjs == 0) { |
282 | 0 | return NULL; |
283 | 0 | } |
284 | 0 | n = nObjs * objSize; |
285 | 0 | if (nObjs < 0 || (size_t)nObjs >= SIZE_MAX / objSize) { |
286 | 0 | gMemError("Bogus memory allocation size"); |
287 | 0 | } |
288 | 0 | return gmalloc64(n); |
289 | 0 | } |
290 | | |
291 | 0 | void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP { |
292 | 0 | int n; |
293 | |
|
294 | 0 | if (nObjs == 0) { |
295 | 0 | if (p) { |
296 | 0 | gfree(p); |
297 | 0 | } |
298 | 0 | return NULL; |
299 | 0 | } |
300 | 0 | n = nObjs * objSize; |
301 | 0 | if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { |
302 | 0 | gMemError("Bogus memory allocation size"); |
303 | 0 | } |
304 | 0 | return grealloc(p, n); |
305 | 0 | } |
306 | | |
307 | 1.19M | void gfree(void *p) { |
308 | | #ifdef DEBUG_MEM |
309 | | size_t size; |
310 | | GMemHdr *hdr; |
311 | | unsigned long *trl, *clr; |
312 | | |
313 | | if (p) { |
314 | | hdr = (GMemHdr *)((char *)p - gMemHdrSize); |
315 | | gMemLock; |
316 | | if (hdr->magic == gMemMagic && |
317 | | ((hdr->prev == NULL) == (hdr == gMemHead)) && |
318 | | ((hdr->next == NULL) == (hdr == gMemTail))) { |
319 | | if (hdr->prev) { |
320 | | hdr->prev->next = hdr->next; |
321 | | } else { |
322 | | gMemHead = hdr->next; |
323 | | } |
324 | | if (hdr->next) { |
325 | | hdr->next->prev = hdr->prev; |
326 | | } else { |
327 | | gMemTail = hdr->prev; |
328 | | } |
329 | | --gMemAlloc; |
330 | | gMemInUse -= hdr->size; |
331 | | gMemUnlock; |
332 | | size = gMemDataSize64(hdr->size); |
333 | | trl = (unsigned long *)((char *)hdr + gMemHdrSize + size); |
334 | | if (*trl != gMemDeadVal) { |
335 | | fprintf(stderr, "Overwrite past end of block %d at address %p\n", |
336 | | hdr->index, p); |
337 | | } |
338 | | for (clr = (unsigned long *)hdr; clr <= trl; ++clr) { |
339 | | *clr = gMemDeadVal; |
340 | | } |
341 | | free(hdr); |
342 | | } else { |
343 | | gMemUnlock; |
344 | | fprintf(stderr, "Attempted to free bad address %p\n", p); |
345 | | } |
346 | | } |
347 | | #else |
348 | 1.19M | if (p) { |
349 | 1.19M | free(p); |
350 | 1.19M | } |
351 | 1.19M | #endif |
352 | 1.19M | } |
353 | | |
354 | 0 | void gMemError(const char *msg) GMEM_EXCEP { |
355 | 0 | #if USE_EXCEPTIONS |
356 | 0 | throw GMemException(); |
357 | | #else |
358 | | fprintf(stderr, "%s\n", msg); |
359 | | exit(1); |
360 | | #endif |
361 | 0 | } |
362 | | |
363 | | #ifdef DEBUG_MEM |
364 | | void gMemReport(FILE *f) { |
365 | | GMemHdr *p; |
366 | | int left; |
367 | | |
368 | | fprintf(f, "%d memory allocations in all\n", gMemIndex); |
369 | | fprintf(f, "maximum memory in use: %zd bytes\n", gMaxMemInUse); |
370 | | left = 0; |
371 | | if (gMemAlloc > 0) { |
372 | | for (p = gMemHead; p; p = p->next) { |
373 | | if (p->index >= 0) { |
374 | | if (!left) { |
375 | | fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc); |
376 | | fprintf(f, " index size\n"); |
377 | | fprintf(f, "-------- --------\n"); |
378 | | left = 1; |
379 | | } |
380 | | fprintf(f, "%8d %8zd\n", p->index, p->size); |
381 | | } |
382 | | } |
383 | | } |
384 | | if (!left) { |
385 | | fprintf(f, "No memory blocks left allocated\n"); |
386 | | } |
387 | | } |
388 | | #endif |
389 | | |
390 | 0 | char *copyString(const char *s) { |
391 | 0 | char *s1; |
392 | |
|
393 | 0 | s1 = (char *)gmalloc((int)strlen(s) + 1); |
394 | 0 | strcpy(s1, s); |
395 | 0 | return s1; |
396 | 0 | } |