-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmemory.c
420 lines (340 loc) · 10.8 KB
/
memory.c
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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
/*
memory.c
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
Copyright (C) 1995 Herb Chong
All rights reserved.
See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <stdio.h>
#include <stdlib.h>
#include "dict.h"
#include "memory.h"
#include "rogue.h"
static char sccsid[] = "%W%\t%G%";
/* Debugging memory allocation code that tries to trap common memory problems
like overwriting storage and stepping on memory pointer chains. If code
doesn't use malloc, free, and realloc a lot, these routines can be left in
as added protection against undetected storage bugs.
*/
/* FENCE_SIZE should be a multiple of sizeof(size_t) to prevent alignment problems.
The code assumes that malloc and realloc return pointers aligned at least on size_t
sized boundaries and that a pointer needs alignment no more strict than that of an
object needed to hold a size_t.
*/
#define FENCE_SIZE (sizeof(size_t) * 1024)
static int memdebug_level = 0;
static DICTIONARY *allocations = NULL;
static FILE *trace_file = NULL;
/* set the debug level */
void mem_debug(const int level)
{
memdebug_level = level;
if (trace_file == NULL)
trace_file = fopen("trace", "w");
/* all except 0, 1, and unknown fall through */
switch(memdebug_level) {
case 2:
fprintf(trace_file, "+++ Memory tracking possible, ");
case 1:
fprintf(trace_file, "+++ Memory debugging enabled, ");
break;
case 0:
fprintf(trace_file, "+++ Memory debugging disabled, ");
break;
default:
fprintf(trace_file, "!!! Unknown memory debug level set, enabling level 1, ");
memdebug_level = 1;
break;
}
fprintf(trace_file, "fence size = %d\n", FENCE_SIZE);
}
/* set memory tracking on or off */
/* turning it off deletes all tracking data */
void mem_tracking(int flag)
{
/* do nothing if debuglevel is too low */
if (memdebug_level < 2)
return;
/* turn on tracking */
if (flag > 0) {
if (allocations != NULL) {
dict_destroy(allocations);
allocations = NULL;
}
allocations = dict_create(8, 100, 4, 20);
if (allocations == NULL) {
fprintf(trace_file, "!!! Unable to allocate tracking table!\n");
abort();
}
}
/* turn off tracking */
else if (allocations != NULL) {
dict_destroy(allocations);
allocations = NULL;
}
}
/* go through all pointers and see if they are OK, aborting if not */
/* always returns 1 if not aborting so that it can be included in */
/* if statement boolean expressions */
int mem_check(char *fname, int linenum)
{
STRING_ENTRY *se;
/* scan of a NULL dictionary always succeeds */
if (allocations == NULL)
return TRUE;
if (!dict_scan_begin(allocations)) {
fprintf(trace_file, "!!! Dictionary scan initialization failed!\n");
abort();
}
fprintf(trace_file, "\n+++ --- Starting pointer scan\n");
fprintf(trace_file, "+++ --- At %s, %d\n", fname, linenum);
/* mem_validate aborts if there is a problem */
while((se = dict_scan_next(allocations)) != NULL)
mem_validate(se->any_ptr);
fprintf(trace_file, "+++ --- Done pointer scan\n\n");
/* always return a good value if execution arrives here */
return 1;
}
/* allocate some memory and initialize header and trailer */
void *mem_malloc(const size_t bytes)
{
char *mem_temp;
size_t real_size = bytes + (FENCE_SIZE << 1);
/* allocate including guard bytes to detect some ways of overwriting of memory areas */
mem_temp = (void *)malloc(real_size);
if (memdebug_level > 0) {
fprintf(trace_file, "+++ Requested size of %ld bytes\n", bytes);
fprintf(trace_file, "+++ Actual malloc of %ld bytes located at %p\n", real_size, mem_temp);
}
/* if allocation succeeded, set management data */
if (mem_temp != NULL) {
size_t i;
char *end;
/* do beginning marker bytes */
for (i = 0; i < FENCE_SIZE - sizeof(size_t); i++)
*mem_temp++ = 145;
/* save size in header too */
if (memdebug_level > 0)
fprintf(trace_file, "*** Requested memory size stored at %p\n", mem_temp);
*(size_t *)mem_temp = bytes;
/* finally, point to storage we are going to hand out */
mem_temp += sizeof(size_t);
/* now, point to trailer bytes and do them */
end = mem_temp + bytes;
for (i = 0; i < FENCE_SIZE; i++)
*end++ = 145;
/* now zap contents to zero */
for (i = 0; i < bytes; i++)
mem_temp[i] = 0;
}
/* track pointer if needed */
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
long temp;
sprintf(key, "%p", mem_temp);
if (dict_insert(allocations, key, 1, (const unsigned long) bytes, mem_temp, &temp) == NULL) {
fprintf(trace_file, "!!! Insert of pointer tracking info failed\n");
abort();
}
}
/* allow caller to do error handling */
if (memdebug_level > 0) {
fprintf(trace_file, "--- Returning pointer of %p\n", mem_temp);
fflush(trace_file);
}
return (void *)mem_temp;
}
/* release some memory, making sure that it was properly allocated */
void mem_free(const void *ptr)
{
char *mem_temp;
size_t mem_size;
size_t i;
if (memdebug_level > 0)
fprintf(trace_file, "+++ Free of memory located at %p\n", ptr);
if (ptr == NULL) {
if (memdebug_level > 0) {
fprintf(trace_file, "!!! Freeing NULL pointer\n");
fflush(trace_file);
}
abort();
}
mem_validate(ptr); /* doesn't return on error */
/* get location of size of area */
mem_temp = (char *)ptr - sizeof(size_t);
/* get and calculate real size */
mem_size = *(size_t *)mem_temp + (FENCE_SIZE << 1);
/* if doing memory tracking */
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
STRING_ENTRY *se;
long temp;
sprintf(key, "%p", ptr);
if ((se = dict_search(allocations, key, &temp)) == NULL) {
fprintf(trace_file, "!!! Deleting pointer not found in tracking info\n");
abort();
}
if (se->count == 0) {
fprintf(trace_file, "!!! Freeing a pointer that has already been freed!\n");
abort();
}
else if (se->flags != mem_size - (FENCE_SIZE << 1)) {
fprintf(trace_file, "!!! Stored size different from tracking size!\n");
abort();
}
/* remember deleted stuff by zeroing the allocation count */
se->count = 0;
se->flags = 0;
}
/* zap bytes being freed */
for (i = 0, mem_temp = (char *)ptr - FENCE_SIZE; i < mem_size; i++, mem_temp++)
*mem_temp = 243;
if (memdebug_level > 0)
fflush(trace_file);
mem_temp = (char *)ptr - FENCE_SIZE;
free((void *)mem_temp);
}
/* reallocate some memory, making sure that it was properly allocated */
void *mem_realloc(const void *ptr, const size_t new_size)
{
char *mem_temp = (char *)ptr;
size_t real_size = new_size + (FENCE_SIZE << 1);
size_t mem_size;
long i;
if (memdebug_level > 0) {
fprintf(trace_file, "+++ Requested size of %ld bytes\n", new_size);
fprintf(trace_file, "+++ Actual realloc of %ld bytes located at %p\n", real_size, mem_temp);
}
if (ptr == NULL) {
if (memdebug_level > 0) {
fprintf(trace_file, "!!! Reallocating NULL pointer\n");
fflush(trace_file);
}
abort();
}
mem_validate(ptr); /* doesn't return on error */
/* if doing memory tracking */
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
STRING_ENTRY *se;
long temp;
sprintf(key, "%p", ptr);
if ((se = dict_search(allocations, key, &temp)) == NULL) {
fprintf(trace_file, "!!! Deleting a pointer not found in tracking info!\n");
abort();
}
/* point to size bytes */
mem_temp = (char *)ptr - sizeof(size_t);
/* get user size */
mem_size = *(size_t *)mem_temp;
if (se->count == 0) {
fprintf(trace_file, "!!! Freeing a pointer that has already been freed!\n");
abort();
}
else if (se->flags != mem_size) {
fprintf(trace_file, "!!! Stored size different from tracking size!\n");
abort();
}
/* remember deleted stuff by zeroing the allocation count */
se->count = 0;
se->flags = 0;
}
/* header marker bytes will be copied by the realloc */
mem_temp = (char *)ptr - FENCE_SIZE;
mem_temp = realloc((void *)mem_temp, real_size);
if (mem_temp != NULL) {
char *end;
/* save size in header too */
mem_temp += FENCE_SIZE - sizeof(size_t);
if (memdebug_level > 0)
fprintf(trace_file, "*** Requested memory size stored at %p\n", mem_temp);
*(size_t *)mem_temp = new_size;
/* finally, point to storage we are going to hand out */
mem_temp += sizeof(size_t);
/* now, point to trailer bytes and do them */
end = mem_temp + new_size;
for (i = 0; i < FENCE_SIZE; i++)
*end++ = 145;
}
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
long temp;
sprintf(key, "%p", mem_temp);
if (dict_insert(allocations, key, 1, (const unsigned long)new_size, mem_temp, &temp) == NULL) {
fprintf(trace_file, "!!! Insert of pointer tracking info failed\n");
abort();
}
}
if (memdebug_level > 0) {
fprintf(trace_file, "--- Returning pointer of %p\n", mem_temp);
fflush(trace_file);
}
return (void *)mem_temp;
}
/* check a pointer to be sure all check bytes are OK. abort if not */
/* always returns 1 if not aborting so that it can be included in */
/* if statement boolean expressions */
int mem_validate(void *ptr)
{
unsigned char *mem_temp = (unsigned char *)ptr;
size_t mem_size;
size_t i;
/* NULL pointers are always valid */
if (ptr == NULL)
return 1;
if (memdebug_level > 0)
fprintf(trace_file, "+++ Checking %p as pointer\n", ptr);
if (memdebug_level > 1 && allocations != NULL) {
char key[16];
STRING_ENTRY *se;
long temp;
sprintf(key, "%p", ptr);
if ((se = dict_search(allocations, key, &temp)) == NULL) {
fprintf(trace_file, "!!! Pointer not found in tracking info!\n");
abort();
}
/* point to size bytes */
mem_temp = (unsigned char *)ptr - sizeof(size_t);
/* get user size */
mem_size = *(size_t *)mem_temp;
if (se->count == 0) {
fprintf(trace_file, "!!! Checking pointer has been freed!\n");
abort();
}
else if (se->flags != mem_size) {
fprintf(trace_file, "!!! Stored size different from tracking size!\n");
abort();
}
}
/* check the header bytes */
mem_temp = (unsigned char *) ptr - FENCE_SIZE;
if (memdebug_level > 0)
fprintf(trace_file, "+++ Real pointer at %p\n", mem_temp);
for (i = 0; i < FENCE_SIZE - sizeof(size_t); i++)
if (*mem_temp++ != 145) {
if (memdebug_level > 0) {
fprintf(trace_file, "!!! The user pointer at %p has been overwritten\n", ptr);
fprintf(trace_file, "!!! Header offset %ld has been changed\n", i - 1);
fflush(trace_file);
}
abort();
}
/* check size */
i = *(size_t *)mem_temp;
if (memdebug_level > 0)
fprintf(trace_file, "*** Stored memory size of %ld bytes in header\n", i);
/* now point to where trailer should be */
mem_temp = (unsigned char *)ptr + i;
for (i = 0; i < FENCE_SIZE; i++)
if (*mem_temp++ != 145) {
if (memdebug_level > 0) {
fprintf(trace_file, "!!! The user pointer at %p has been overwritten\n", ptr);
fprintf(trace_file, "!!! Trailer offset %ld has been changed\n", i - 1);
fflush(trace_file);
}
abort();
}
if (memdebug_level > 0)
fflush(trace_file);
return 1;
}