gmem.cc 7.03 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1 2 3 4 5 6 7 8
/*
 * gmem.c
 *
 * Memory routines with out-of-memory checking.
 *
 * Copyright 1996-2003 Glyph & Cog, LLC
 */

9 10 11 12
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
13 14 15
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
16
// Copyright (C) 2005 Takashi Iwai <tiwai@suse.de>
17
// Copyright (C) 2007-2010, 2012 Albert Astals Cid <aacid@kde.org>
18 19 20 21 22 23 24
// Copyright (C) 2008 Jonathan Kew <jonathan_kew@sil.org>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

Kristian Høgsberg's avatar
Kristian Høgsberg committed
25 26 27 28 29
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
30
#include <limits.h>
Kristian Høgsberg's avatar
Kristian Høgsberg committed
31 32 33 34 35
#include "gmem.h"

#ifdef DEBUG_MEM

typedef struct _GMemHdr {
36
  unsigned int magic;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
37 38
  int size;
  int index;
39
  struct _GMemHdr *next, *prev;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
40 41 42 43 44
} GMemHdr;

#define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7)
#define gMemTrlSize (sizeof(long))

45 46
#define gMemMagic 0xabcd9999

Kristian Høgsberg's avatar
Kristian Høgsberg committed
47 48 49 50 51 52 53 54 55 56
#if gmemTrlSize==8
#define gMemDeadVal 0xdeadbeefdeadbeefUL
#else
#define gMemDeadVal 0xdeadbeefUL
#endif

/* round data size so trailer will be aligned */
#define gMemDataSize(size) \
  ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)

57 58
static GMemHdr *gMemHead = NULL;
static GMemHdr *gMemTail = NULL;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
59 60 61

static int gMemIndex = 0;
static int gMemAlloc = 0;
62
static int gMemInUse = 0;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
63 64 65

#endif /* DEBUG_MEM */

Albert Astals Cid's avatar
Albert Astals Cid committed
66
inline static void *gmalloc(size_t size, bool checkoverflow) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
67
#ifdef DEBUG_MEM
68
  int size1;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
69 70 71 72 73
  char *mem;
  GMemHdr *hdr;
  void *data;
  unsigned long *trl, *p;

74
  if (size == 0) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
75
    return NULL;
76
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
77 78 79
  size1 = gMemDataSize(size);
  if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) {
    fprintf(stderr, "Out of memory\n");
80 81
    if (checkoverflow) return NULL;
    else exit(1);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
82 83 84 85
  }
  hdr = (GMemHdr *)mem;
  data = (void *)(mem + gMemHdrSize);
  trl = (unsigned long *)(mem + gMemHdrSize + size1);
86
  hdr->magic = gMemMagic;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
87 88
  hdr->size = size;
  hdr->index = gMemIndex++;
89 90 91 92 93 94 95 96 97
  if (gMemTail) {
    gMemTail->next = hdr;
    hdr->prev = gMemTail;
    gMemTail = hdr;
  } else {
    hdr->prev = NULL;
    gMemHead = gMemTail = hdr;
  }
  hdr->next = NULL;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
98
  ++gMemAlloc;
99
  gMemInUse += size;
100
  for (p = (unsigned long *)data; p <= trl; ++p) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
101
    *p = gMemDeadVal;
102
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
103 104 105 106
  return data;
#else
  void *p;

107
  if (size == 0) {
108
    return nullptr;
109
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
110 111
  if (!(p = malloc(size))) {
    fprintf(stderr, "Out of memory\n");
112
    if (checkoverflow) return nullptr;
113
    else exit(1);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
114 115 116 117 118
  }
  return p;
#endif
}

Albert Astals Cid's avatar
Albert Astals Cid committed
119
void *gmalloc(size_t size) {
120 121 122
  return gmalloc(size, false);
}

Albert Astals Cid's avatar
Albert Astals Cid committed
123
void *gmalloc_checkoverflow(size_t size) {
124 125 126
  return gmalloc(size, true);
}

Albert Astals Cid's avatar
Albert Astals Cid committed
127
inline static void *grealloc(void *p, size_t size, bool checkoverflow) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
128 129 130
#ifdef DEBUG_MEM
  GMemHdr *hdr;
  void *q;
131
  int oldSize;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
132

133
  if (size == 0) {
134
    if (p) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
135
      gfree(p);
136
    }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
137 138 139 140 141
    return NULL;
  }
  if (p) {
    hdr = (GMemHdr *)((char *)p - gMemHdrSize);
    oldSize = hdr->size;
142
    q = gmalloc(size, checkoverflow);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
143 144 145
    memcpy(q, p, size < oldSize ? size : oldSize);
    gfree(p);
  } else {
146
    q = gmalloc(size, checkoverflow);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
147 148 149 150 151
  }
  return q;
#else
  void *q;

152
  if (size == 0) {
153
    if (p) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
154
      free(p);
155
    }
156
    return nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
157
  }
158
  if (p) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
159
    q = realloc(p, size);
160
  } else {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
161
    q = malloc(size);
162
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
163 164
  if (!q) {
    fprintf(stderr, "Out of memory\n");
165
    if (checkoverflow) return nullptr;
166
    else exit(1);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
167 168 169 170 171
  }
  return q;
#endif
}

Albert Astals Cid's avatar
Albert Astals Cid committed
172
void *grealloc(void *p, size_t size) {
173 174
  return grealloc(p, size, false);
}
175

Albert Astals Cid's avatar
Albert Astals Cid committed
176
void *grealloc_checkoverflow(void *p, size_t size) {
177
  return grealloc(p, size, true);
178 179
}

Albert Astals Cid's avatar
Albert Astals Cid committed
180
inline static void *gmallocn(int nObjs, int objSize, bool checkoverflow) {
181
  if (nObjs == 0) {
182
    return nullptr;
183 184 185
  }
  if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
    fprintf(stderr, "Bogus memory allocation size\n");
186
    if (checkoverflow) return nullptr;
187
    else exit(1);
188
  }
189
  const int n = nObjs * objSize;
190
  return gmalloc(n, checkoverflow);
191 192
}

Albert Astals Cid's avatar
Albert Astals Cid committed
193
void *gmallocn(int nObjs, int objSize) {
194 195
  return gmallocn(nObjs, objSize, false);
}
196

Albert Astals Cid's avatar
Albert Astals Cid committed
197
void *gmallocn_checkoverflow(int nObjs, int objSize) {
198
  return gmallocn(nObjs, objSize, true);
199 200
}

Albert Astals Cid's avatar
Albert Astals Cid committed
201
inline static void *gmallocn3(int a, int b, int c, bool checkoverflow) {
202 203 204
  int n = a * b;
  if (b <= 0 || a < 0 || a >= INT_MAX / b) {
    fprintf(stderr, "Bogus memory allocation size\n");
205
    if (checkoverflow) return nullptr;
206 207 208 209 210
    else exit(1);
  }
  return gmallocn(n, c, checkoverflow);
}

Albert Astals Cid's avatar
Albert Astals Cid committed
211
void *gmallocn3(int a, int b, int c) {
212 213 214
  return gmallocn3(a, b, c, false);
}

Albert Astals Cid's avatar
Albert Astals Cid committed
215
void *gmallocn3_checkoverflow(int a, int b, int c) {
216 217 218
  return gmallocn3(a, b, c, true);
}

Albert Astals Cid's avatar
Albert Astals Cid committed
219
inline static void *greallocn(void *p, int nObjs, int objSize, bool checkoverflow) {
220 221 222 223
  if (nObjs == 0) {
    if (p) {
      gfree(p);
    }
224
    return nullptr;
225 226 227
  }
  if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
    fprintf(stderr, "Bogus memory allocation size\n");
228 229
    if (checkoverflow) {
      gfree(p);
230
      return nullptr;
231 232 233
    } else {
      exit(1);
    }
234
  }
235
  const int n = nObjs * objSize;
236 237 238
  return grealloc(p, n, checkoverflow);
}

Albert Astals Cid's avatar
Albert Astals Cid committed
239
void *greallocn(void *p, int nObjs, int objSize) {
240 241 242
  return greallocn(p, nObjs, objSize, false);
}

Albert Astals Cid's avatar
Albert Astals Cid committed
243
void *greallocn_checkoverflow(void *p, int nObjs, int objSize) {
244
  return greallocn(p, nObjs, objSize, true);
245 246
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
247 248
void gfree(void *p) {
#ifdef DEBUG_MEM
249
  int size;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
250 251 252 253 254
  GMemHdr *hdr;
  unsigned long *trl, *clr;

  if (p) {
    hdr = (GMemHdr *)((char *)p - gMemHdrSize);
255 256 257 258 259 260 261 262 263 264 265 266 267
    if (hdr->magic == gMemMagic &&
	((hdr->prev == NULL) == (hdr == gMemHead)) &&
	((hdr->next == NULL) == (hdr == gMemTail))) {
      if (hdr->prev) {
	hdr->prev->next = hdr->next;
      } else {
	gMemHead = hdr->next;
      }
      if (hdr->next) {
	hdr->next->prev = hdr->prev;
      } else {
	gMemTail = hdr->prev;
      }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
268
      --gMemAlloc;
269
      gMemInUse -= hdr->size;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
270 271 272 273 274 275
      size = gMemDataSize(hdr->size);
      trl = (unsigned long *)((char *)hdr + gMemHdrSize + size);
      if (*trl != gMemDeadVal) {
	fprintf(stderr, "Overwrite past end of block %d at address %p\n",
		hdr->index, p);
      }
276
      for (clr = (unsigned long *)hdr; clr <= trl; ++clr) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
277
	*clr = gMemDeadVal;
278
      }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
279 280 281 282 283 284
      free(hdr);
    } else {
      fprintf(stderr, "Attempted to free bad address %p\n", p);
    }
  }
#else
285 286 287
  if (p) {
    free(p);
  }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
288 289 290 291 292 293 294 295 296 297 298 299
#endif
}

#ifdef DEBUG_MEM
void gMemReport(FILE *f) {
  GMemHdr *p;

  fprintf(f, "%d memory allocations in all\n", gMemIndex);
  if (gMemAlloc > 0) {
    fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc);
    fprintf(f, " index     size\n");
    fprintf(f, "-------- --------\n");
300 301
    for (p = gMemHead; p; p = p->next) {
      fprintf(f, "%8d %8d\n", p->index, p->size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
302 303 304 305 306 307 308
    }
  } else {
    fprintf(f, "No memory blocks left allocated\n");
  }
}
#endif

309
char *copyString(const char *s) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
310 311 312 313 314 315
  char *s1;

  s1 = (char *)gmalloc(strlen(s) + 1);
  strcpy(s1, s);
  return s1;
}
316 317 318 319 320 321 322

char *gstrndup(const char *s, size_t n) {
  char *s1 = (char*)gmalloc(n + 1); /* cannot return NULL for size > 0 */
  s1[n] = '\0';
  memcpy(s1, s, n);
  return s1;
}