1 /*
2  * gmem.c
3  *
4  * Memory routines with out-of-memory checking.
5  *
6  * Copyright 1996-2003 Glyph & Cog, LLC
7  */
8 
9 //========================================================================
10 //
11 // Modified under the Poppler project - http://poppler.freedesktop.org
12 //
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
15 //
16 // Copyright (C) 2005 Takashi Iwai <tiwai@suse.de>
17 // Copyright (C) 2007-2010, 2012 Albert Astals Cid <aacid@kde.org>
18 // Copyright (C) 2008 Jonathan Kew <jonathan_kew@sil.org>
19 //
20 // To see a description of the changes please see the Changelog file that
21 // came with your tarball or type make ChangeLog if you are building from git
22 //
23 //========================================================================
24 
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stddef.h>
29 #include <string.h>
30 #include <limits.h>
31 #include "gmem.h"
32 
33 #ifdef DEBUG_MEM
34 
35 typedef struct _GMemHdr {
36   unsigned int magic;
37   int size;
38   int index;
39   struct _GMemHdr *next, *prev;
40 } GMemHdr;
41 
42 #define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7)
43 #define gMemTrlSize (sizeof(long))
44 
45 #define gMemMagic 0xabcd9999
46 
47 #if gmemTrlSize==8
48 #define gMemDeadVal 0xdeadbeefdeadbeefUL
49 #else
50 #define gMemDeadVal 0xdeadbeefUL
51 #endif
52 
53 /* round data size so trailer will be aligned */
54 #define gMemDataSize(size) \
55   ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)
56 
57 static GMemHdr *gMemHead = NULL;
58 static GMemHdr *gMemTail = NULL;
59 
60 static int gMemIndex = 0;
61 static int gMemAlloc = 0;
62 static int gMemInUse = 0;
63 
64 #endif /* DEBUG_MEM */
65 
gmalloc(size_t size,bool checkoverflow)66 inline static void *gmalloc(size_t size, bool checkoverflow) {
67 #ifdef DEBUG_MEM
68   int size1;
69   char *mem;
70   GMemHdr *hdr;
71   void *data;
72   unsigned long *trl, *p;
73 
74   if (size == 0) {
75     return NULL;
76   }
77   size1 = gMemDataSize(size);
78   if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) {
79     fprintf(stderr, "Out of memory\n");
80     if (checkoverflow) return NULL;
81     else exit(1);
82   }
83   hdr = (GMemHdr *)mem;
84   data = (void *)(mem + gMemHdrSize);
85   trl = (unsigned long *)(mem + gMemHdrSize + size1);
86   hdr->magic = gMemMagic;
87   hdr->size = size;
88   hdr->index = gMemIndex++;
89   if (gMemTail) {
90     gMemTail->next = hdr;
91     hdr->prev = gMemTail;
92     gMemTail = hdr;
93   } else {
94     hdr->prev = NULL;
95     gMemHead = gMemTail = hdr;
96   }
97   hdr->next = NULL;
98   ++gMemAlloc;
99   gMemInUse += size;
100   for (p = (unsigned long *)data; p <= trl; ++p) {
101     *p = gMemDeadVal;
102   }
103   return data;
104 #else
105   void *p;
106 
107   if (size == 0) {
108     return NULL;
109   }
110   if (!(p = malloc(size))) {
111     fprintf(stderr, "Out of memory\n");
112     if (checkoverflow) return NULL;
113     else exit(1);
114   }
115   return p;
116 #endif
117 }
118 
gmalloc(size_t size)119 void *gmalloc(size_t size) {
120   return gmalloc(size, false);
121 }
122 
gmalloc_checkoverflow(size_t size)123 void *gmalloc_checkoverflow(size_t size) {
124   return gmalloc(size, true);
125 }
126 
grealloc(void * p,size_t size,bool checkoverflow)127 inline static void *grealloc(void *p, size_t size, bool checkoverflow) {
128 #ifdef DEBUG_MEM
129   GMemHdr *hdr;
130   void *q;
131   int oldSize;
132 
133   if (size == 0) {
134     if (p) {
135       gfree(p);
136     }
137     return NULL;
138   }
139   if (p) {
140     hdr = (GMemHdr *)((char *)p - gMemHdrSize);
141     oldSize = hdr->size;
142     q = gmalloc(size, checkoverflow);
143     memcpy(q, p, size < oldSize ? size : oldSize);
144     gfree(p);
145   } else {
146     q = gmalloc(size, checkoverflow);
147   }
148   return q;
149 #else
150   void *q;
151 
152   if (size == 0) {
153     if (p) {
154       free(p);
155     }
156     return NULL;
157   }
158   if (p) {
159     q = realloc(p, size);
160   } else {
161     q = malloc(size);
162   }
163   if (!q) {
164     fprintf(stderr, "Out of memory\n");
165     if (checkoverflow) return NULL;
166     else exit(1);
167   }
168   return q;
169 #endif
170 }
171 
grealloc(void * p,size_t size)172 void *grealloc(void *p, size_t size) {
173   return grealloc(p, size, false);
174 }
175 
grealloc_checkoverflow(void * p,size_t size)176 void *grealloc_checkoverflow(void *p, size_t size) {
177   return grealloc(p, size, true);
178 }
179 
gmallocn(int nObjs,int objSize,bool checkoverflow)180 inline static void *gmallocn(int nObjs, int objSize, bool checkoverflow) {
181   int n;
182 
183   if (nObjs == 0) {
184     return NULL;
185   }
186   n = nObjs * objSize;
187   if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
188     fprintf(stderr, "Bogus memory allocation size\n");
189     if (checkoverflow) return NULL;
190     else exit(1);
191   }
192   return gmalloc(n, checkoverflow);
193 }
194 
gmallocn(int nObjs,int objSize)195 void *gmallocn(int nObjs, int objSize) {
196   return gmallocn(nObjs, objSize, false);
197 }
198 
gmallocn_checkoverflow(int nObjs,int objSize)199 void *gmallocn_checkoverflow(int nObjs, int objSize) {
200   return gmallocn(nObjs, objSize, true);
201 }
202 
gmallocn3(int a,int b,int c,bool checkoverflow)203 inline static void *gmallocn3(int a, int b, int c, bool checkoverflow) {
204   int n = a * b;
205   if (b <= 0 || a < 0 || a >= INT_MAX / b) {
206     fprintf(stderr, "Bogus memory allocation size\n");
207     if (checkoverflow) return NULL;
208     else exit(1);
209   }
210   return gmallocn(n, c, checkoverflow);
211 }
212 
gmallocn3(int a,int b,int c)213 void *gmallocn3(int a, int b, int c) {
214   return gmallocn3(a, b, c, false);
215 }
216 
gmallocn3_checkoverflow(int a,int b,int c)217 void *gmallocn3_checkoverflow(int a, int b, int c) {
218   return gmallocn3(a, b, c, true);
219 }
220 
greallocn(void * p,int nObjs,int objSize,bool checkoverflow)221 inline static void *greallocn(void *p, int nObjs, int objSize, bool checkoverflow) {
222   int n;
223 
224   if (nObjs == 0) {
225     if (p) {
226       gfree(p);
227     }
228     return NULL;
229   }
230   n = nObjs * objSize;
231   if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
232     fprintf(stderr, "Bogus memory allocation size\n");
233     if (checkoverflow) {
234       gfree(p);
235       return NULL;
236     } else {
237       exit(1);
238     }
239   }
240   return grealloc(p, n, checkoverflow);
241 }
242 
greallocn(void * p,int nObjs,int objSize)243 void *greallocn(void *p, int nObjs, int objSize) {
244   return greallocn(p, nObjs, objSize, false);
245 }
246 
greallocn_checkoverflow(void * p,int nObjs,int objSize)247 void *greallocn_checkoverflow(void *p, int nObjs, int objSize) {
248   return greallocn(p, nObjs, objSize, true);
249 }
250 
gfree(void * p)251 void gfree(void *p) {
252 #ifdef DEBUG_MEM
253   int size;
254   GMemHdr *hdr;
255   unsigned long *trl, *clr;
256 
257   if (p) {
258     hdr = (GMemHdr *)((char *)p - gMemHdrSize);
259     if (hdr->magic == gMemMagic &&
260 	((hdr->prev == NULL) == (hdr == gMemHead)) &&
261 	((hdr->next == NULL) == (hdr == gMemTail))) {
262       if (hdr->prev) {
263 	hdr->prev->next = hdr->next;
264       } else {
265 	gMemHead = hdr->next;
266       }
267       if (hdr->next) {
268 	hdr->next->prev = hdr->prev;
269       } else {
270 	gMemTail = hdr->prev;
271       }
272       --gMemAlloc;
273       gMemInUse -= hdr->size;
274       size = gMemDataSize(hdr->size);
275       trl = (unsigned long *)((char *)hdr + gMemHdrSize + size);
276       if (*trl != gMemDeadVal) {
277 	fprintf(stderr, "Overwrite past end of block %d at address %p\n",
278 		hdr->index, p);
279       }
280       for (clr = (unsigned long *)hdr; clr <= trl; ++clr) {
281 	*clr = gMemDeadVal;
282       }
283       free(hdr);
284     } else {
285       fprintf(stderr, "Attempted to free bad address %p\n", p);
286     }
287   }
288 #else
289   if (p) {
290     free(p);
291   }
292 #endif
293 }
294 
295 #ifdef DEBUG_MEM
gMemReport(FILE * f)296 void gMemReport(FILE *f) {
297   GMemHdr *p;
298 
299   fprintf(f, "%d memory allocations in all\n", gMemIndex);
300   if (gMemAlloc > 0) {
301     fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc);
302     fprintf(f, " index     size\n");
303     fprintf(f, "-------- --------\n");
304     for (p = gMemHead; p; p = p->next) {
305       fprintf(f, "%8d %8d\n", p->index, p->size);
306     }
307   } else {
308     fprintf(f, "No memory blocks left allocated\n");
309   }
310 }
311 #endif
312 
copyString(const char * s)313 char *copyString(const char *s) {
314   char *s1;
315 
316   s1 = (char *)gmalloc(strlen(s) + 1);
317   strcpy(s1, s);
318   return s1;
319 }
320 
gstrndup(const char * s,size_t n)321 char *gstrndup(const char *s, size_t n) {
322   char *s1 = (char*)gmalloc(n + 1); /* cannot return NULL for size > 0 */
323   s1[n] = '\0';
324   memcpy(s1, s, n);
325   return s1;
326 }
327