comparison urogue/memory.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children c4b12d2d1dcd
comparison
equal deleted inserted replaced
253:d9badb9c0179 256:c495a4f288c6
1 /*
2 memory.c
3
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5 Copyright (C) 1995 Herb Chong
6 All rights reserved.
7
8 See the file LICENSE.TXT for full copyright and licensing information.
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include "dict.h"
15 #include "memory.h"
16 #include "rogue.h"
17
18 static char sccsid[] = "%W%\t%G%";
19
20 /* Debugging memory allocation code that tries to trap common memory problems
21 like overwriting storage and stepping on memory pointer chains. If code
22 doesn't use malloc, free, and realloc a lot, these routines can be left in
23 as added protection against undetected storage bugs.
24 */
25
26 /* FENCE_SIZE should be a multiple of sizeof(size_t) to prevent alignment problems.
27 The code assumes that malloc and realloc return pointers aligned at least on size_t
28 sized boundaries and that a pointer needs alignment no more strict than that of an
29 object needed to hold a size_t.
30 */
31
32 #define FENCE_SIZE (sizeof(size_t) * 1024)
33
34 static int memdebug_level = 0;
35 static DICTIONARY *allocations = NULL;
36 static FILE *trace_file = NULL;
37
38 /* set the debug level */
39 void mem_debug(const int level)
40 {
41 memdebug_level = level;
42
43 if (trace_file == NULL)
44 trace_file = fopen("trace", "w");
45
46 /* all except 0, 1, and unknown fall through */
47 switch(memdebug_level) {
48 case 2:
49 fprintf(trace_file, "+++ Memory tracking possible, ");
50 case 1:
51 fprintf(trace_file, "+++ Memory debugging enabled, ");
52 break;
53 case 0:
54 fprintf(trace_file, "+++ Memory debugging disabled, ");
55 break;
56 default:
57 fprintf(trace_file, "!!! Unknown memory debug level set, enabling level 1, ");
58 memdebug_level = 1;
59 break;
60 }
61 fprintf(trace_file, "fence size = %d\n", FENCE_SIZE);
62 }
63
64 /* set memory tracking on or off */
65 /* turning it off deletes all tracking data */
66 void mem_tracking(int flag)
67 {
68 /* do nothing if debuglevel is too low */
69 if (memdebug_level < 2)
70 return;
71
72 /* turn on tracking */
73 if (flag > 0) {
74 if (allocations != NULL) {
75 dict_destroy(allocations);
76 allocations = NULL;
77 }
78 allocations = dict_create(8, 100, 4, 20);
79 if (allocations == NULL) {
80 fprintf(trace_file, "!!! Unable to allocate tracking table!\n");
81 abort();
82 }
83 }
84 /* turn off tracking */
85 else if (allocations != NULL) {
86 dict_destroy(allocations);
87 allocations = NULL;
88 }
89 }
90
91 /* go through all pointers and see if they are OK, aborting if not */
92 /* always returns 1 if not aborting so that it can be included in */
93 /* if statement boolean expressions */
94 int mem_check(char *fname, int linenum)
95 {
96 STRING_ENTRY *se;
97
98 /* scan of a NULL dictionary always succeeds */
99 if (allocations == NULL)
100 return TRUE;
101
102 if (!dict_scan_begin(allocations)) {
103 fprintf(trace_file, "!!! Dictionary scan initialization failed!\n");
104 abort();
105 }
106
107 fprintf(trace_file, "\n+++ --- Starting pointer scan\n");
108 fprintf(trace_file, "+++ --- At %s, %d\n", fname, linenum);
109
110 /* mem_validate aborts if there is a problem */
111 while((se = dict_scan_next(allocations)) != NULL)
112 mem_validate(se->any_ptr);
113
114 fprintf(trace_file, "+++ --- Done pointer scan\n\n");
115
116 /* always return a good value if execution arrives here */
117 return 1;
118 }
119
120 /* allocate some memory and initialize header and trailer */
121 void *mem_malloc(const size_t bytes)
122 {
123 char *mem_temp;
124 size_t real_size = bytes + (FENCE_SIZE << 1);
125
126 /* allocate including guard bytes to detect some ways of overwriting of memory areas */
127 mem_temp = (void *)malloc(real_size);
128 if (memdebug_level > 0) {
129 fprintf(trace_file, "+++ Requested size of %ld bytes\n", bytes);
130 fprintf(trace_file, "+++ Actual malloc of %ld bytes located at %p\n", real_size, mem_temp);
131 }
132
133 /* if allocation succeeded, set management data */
134 if (mem_temp != NULL) {
135 size_t i;
136 char *end;
137
138 /* do beginning marker bytes */
139 for (i = 0; i < FENCE_SIZE - sizeof(size_t); i++)
140 *mem_temp++ = 145;
141
142 /* save size in header too */
143 if (memdebug_level > 0)
144 fprintf(trace_file, "*** Requested memory size stored at %p\n", mem_temp);
145 *(size_t *)mem_temp = bytes;
146
147 /* finally, point to storage we are going to hand out */
148 mem_temp += sizeof(size_t);
149
150 /* now, point to trailer bytes and do them */
151 end = mem_temp + bytes;
152 for (i = 0; i < FENCE_SIZE; i++)
153 *end++ = 145;
154
155 /* now zap contents to zero */
156 for (i = 0; i < bytes; i++)
157 mem_temp[i] = 0;
158 }
159
160 /* track pointer if needed */
161 if (memdebug_level > 1 && allocations != NULL) {
162 char key[16];
163 long temp;
164
165 sprintf(key, "%p", mem_temp);
166 if (dict_insert(allocations, key, 1, (const unsigned long) bytes, mem_temp, &temp) == NULL) {
167 fprintf(trace_file, "!!! Insert of pointer tracking info failed\n");
168 abort();
169 }
170 }
171
172 /* allow caller to do error handling */
173 if (memdebug_level > 0) {