File: memdebug.c

package info (click to toggle)
dircproxy 1.0.5-5etch1
  • links: PTS
  • area: main
  • in suites: etch
  • size: 1,120 kB
  • ctags: 740
  • sloc: ansic: 9,466; sh: 2,946; makefile: 113; perl: 70
file content (310 lines) | stat: -rw-r--r-- 8,487 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/* dircproxy
 * Copyright (C) 2002 Scott James Remnant <scott@netsplit.com>.
 * All Rights Reserved.
 *
 * memdebug.c
 *  - wrappers to memory allocation functions
 *  - memory leak tracing
 *  - buffer overrun detection
 *
 * The idea of these is that lots of extra memory is used to store
 * information about memory allocations, and to check things don't
 * get accidentally overrun.  This is purely debug, you should
 * NEVER use this in a real program.
 * --
 * @(#) $Id: memdebug.c,v 1.8 2001/12/21 20:15:55 keybuk Exp $
 *
 * This file is distributed according to the GNU General Public
 * License.  For full details, read the top of 'main.c' or the
 * file called COPYING that was distributed with this code.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Define MIN() */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif /* MIN */

/* This is the structure that goes in front of EVERY chunk or hunk of
   memory alloc'd. Take a good long look at how big it is, imagine your
   memory full of these. I think its best to only use this for debugging
   purposes. Okay? */
struct memstamp {
  unsigned short magic;
  unsigned long allocnum;
  size_t size;
  char *file;
  int line;
  struct memstamp *next;
};

/* For statistics */
struct memcount {
  char *file;
  unsigned long count;
  struct memcount *next;
};

/* definition of the magic number */
#define MEMMAGIC 0xDC10

/* data put before and after the memory to detect overruns */
#define MEMPREBUFF "yankydoodledandy"
#define MEMPOSTBUFF "itwasacolddayinhell"

/* function prototypes - don't include the .h as it'll all go *boom* */
void *mem_malloc(size_t, char *, int);
void *mem_realloc(void *, size_t, char *, int);
void mem_report(char *);

/* variables */
static unsigned long memalloccount = 0L;
static unsigned long memfreecount = 0L;
static unsigned long memusage = 0L;
static struct memstamp *memstamplist = NULL;
static struct memcount *memcounts = 0;

/* Insert a new memory stamp onto the list */
static void _mem_insert(struct memstamp *ms) {
  ms->next = memstamplist;
  memstamplist = ms;
}

/* Delete a memory stamp from the list */
static void _mem_delete(struct memstamp *ms) {
  struct memstamp *msptr;

  if (memstamplist != ms) {
    msptr = memstamplist;
    while (msptr->next != NULL) {
      if (msptr->next == ms) {
        msptr->next = ms->next;
        return;
      }
      msptr = msptr->next;
    }
    fprintf(stderr, "MEM: bugger! attempted delete of phantom stamp.\n");

  } else {
    memstamplist = ms->next;
  }
}

/* Check for overruns */
static void _mem_checkpad(struct memstamp *ms, char *file, int line) {
  char *ptr;

  ptr = (char *)ms + sizeof(struct memstamp);
  if (strncmp(ptr, MEMPREBUFF, strlen(MEMPREBUFF))) {
    char *data;

    data = (char *)malloc(strlen(MEMPREBUFF) + 1);
    strncpy(data, ptr, strlen(MEMPREBUFF));
    data[strlen(MEMPREBUFF)] = 0;

    fprintf(stderr, "MEM: possible underun detected by (%s/%d) "
           "alloc at (%s/%d).\n", file ? file : "debug code",
           file ? line : 0, ms->file ? ms->file : "debug code",
           ms->file ? ms->line : 0);
    fprintf(stderr, "     [%s:%s]\n", MEMPREBUFF, data);
    free(data);
  }

  ptr = (char *)ptr + strlen(MEMPREBUFF) + ms->size;
  if (strncmp(ptr, MEMPOSTBUFF, strlen(MEMPOSTBUFF))) {
    char *data;

    data = (char *)malloc(strlen(MEMPOSTBUFF) + 1);
    strncpy(data, ptr, strlen(MEMPOSTBUFF));
    data[strlen(MEMPOSTBUFF)] = 0;

    fprintf(stderr, "MEM: possible overun detected by (%s/%d) "
           "alloc at (%s/%d).\n", file ? file : "debug code", file ? line : 0,
           ms->file ? ms->file : "debug code", ms->file ? ms->line : 0);
    fprintf(stderr, "     [%s:%s]\n", MEMPOSTBUFF, data);
    free(data);
  }
}

/* Wrapper around malloc() which adds a memstamp to the front */
void *mem_malloc(size_t size, char *file, int line) {
  struct memstamp *ms;
  struct memcount *mc;

  if (size > 0) {
    unsigned long malloc_sz;
    char *preptr, *postptr;

    malloc_sz = (sizeof(struct memstamp) + strlen(MEMPREBUFF) + size
                 + strlen(MEMPOSTBUFF));

    if (!(ms = (struct memstamp *)malloc(malloc_sz))) {
      fprintf(stderr, "MEM: malloc failed to alloc %lu(%lu) bytes (%s/%d)\n",
              (unsigned long)malloc_sz, (unsigned long)size,
              file ? file : "debug code", file ? line : 0);
      abort();
    }

    if (file && strlen(file)) {
      mc = memcounts;
      while (mc) {
        if (!strcmp(mc->file, file)) {
          mc->count++;
          break;
        }

        mc = mc->next;
      }
      if (!mc) {
        if (!(mc = (struct memcount *)malloc(sizeof(struct memcount)))) {
          fprintf(stderr, "MEM: malloc failed to alloc %lu bytes (%s/%d)\n",
                  (unsigned long)(sizeof(struct memcount)), file, line);
          abort();
        }
   
        if (!(mc->file = (char *)malloc(strlen(file) + 1))) {
          fprintf(stderr, "MEM: malloc failed to alloc %lu bytes (%s/%d)\n",
                  (unsigned long)(strlen(file) + 1), file, line);
          abort();
        }
   
        strcpy(mc->file, file);
        mc->count = 1;
        mc->next = memcounts;
        memcounts = mc;
      }

      if (!(ms->file = (char *)malloc(strlen(file) + 1))) {
        fprintf(stderr, "MEM: malloc failed to alloc %lu bytes (%s/%d)\n",
                (unsigned long)(strlen(file) + 1), file, line);
        abort();
      }
      strcpy(ms->file, file);
      ms->allocnum = memalloccount++;
      ms->line = line;

#if 0
      fprintf(stderr, "MEM: malloc of %lu bytes (%s/%d)\n",
              (unsigned long)size, file, line);
#endif
    } else {
      ms->file = 0;
      ms->allocnum = 0;
      ms->line = 0;
    }
    ms->magic = MEMMAGIC;
    ms->size = size;
    memusage += size;
    _mem_insert(ms);

    preptr = (char *)ms;
    preptr += sizeof(struct memstamp);
    strncpy(preptr, MEMPREBUFF, strlen(MEMPREBUFF));
    preptr += strlen(MEMPREBUFF);

    postptr = preptr;
    postptr += size;
    strncpy(postptr, MEMPOSTBUFF, strlen(MEMPOSTBUFF));

    return (void *)preptr;
  } else {
    return NULL;
  }
}

/* Wrapper around realloc() which adds a memstamp to the front */
void *mem_realloc(void *ptr, size_t size, char *file, int line) {
  unsigned long data_off;
  struct memstamp *ms;
  void *block;

  if (ptr == NULL)
    return mem_malloc(size, file, line);

  data_off = sizeof(struct memstamp) + strlen(MEMPREBUFF);

  ms = (struct memstamp *)((char *)ptr - data_off);
  if (ms->magic != MEMMAGIC) {
    fprintf(stderr, "MEM: %s of illegal block (%s/%d)\n",
            (size > 0) ? "realloc" : "free", file ? file : "debug code",
            file ? line : 0);
    return NULL;
  }

  _mem_checkpad(ms, file, line);

  block = NULL;

  if (size > 0) {
    block = mem_malloc(size, file, line);
    if (size < ms->size)
      memcpy(block, (char *)ms + data_off, size);
    else
      memcpy(block, (char *)ms + data_off, ms->size);
  }

  if (ms->file)
    memfreecount++;
  memusage -= ms->size;
  _mem_delete(ms);
  free(ms->file);
  free(ms);
  return block;
}

/* Reports current memory usage and shows what was malloc()d where */
void mem_report(char *message) {
  struct memstamp *msptr;
  struct memcount *mc;
  
  msptr = memstamplist;
  printf("MEM:REPORT%s%s%s %lu bytes in use [%lu alloc][%lu free]\n",
         message ? " (" : "", message ? message : "", message ? ")" : "",
         memusage, memalloccount, memfreecount);

  mc = memcounts;
  while (mc) {
    unsigned long i, t;

    printf("%16s %8lu ", mc->file, mc->count);

    t = ((double)mc->count / (double)memalloccount) * 40;
    for (i = 0; i < t; i++)
      printf("#");
    printf("\n");

    mc = mc->next;
  }
  printf("\n");
  
  while (msptr) {
    if (message) {
      int i;
      
      printf("     %s/%d - %lu bytes alloc'd [an:%lu]\n",
             msptr->file ? msptr->file : "debug code",
             msptr->file ? msptr->line : 0, (unsigned long)msptr->size,
             msptr->file ? msptr->allocnum : 0);

      printf("     [");
      for (i = 0; i <= MIN(msptr->size, 70); i++) {
        int c;

        c = *((char *)msptr + sizeof(struct memstamp) + strlen(MEMPREBUFF) + i);
        if ((c >= 32) && (c <= 127)) {
          printf("%c", c);
        } else if (c) {
          printf("");
        } else {
          break;
        }
      }
      printf("]\n");
    }
    _mem_checkpad(msptr, "report", 0);
    msptr = msptr->next;
  }
}