JWM Source Documentation
debug.c
Go to the documentation of this file.
1 
10 #include "debug.h"
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <string.h>
14 
16 void Debug(const char *str, ...)
17 {
18 #ifdef DEBUG
19 
20  va_list ap;
21  va_start(ap, str);
22  Assert(str);
23  fprintf(stderr, "DEBUG: ");
24  vfprintf(stderr, str, ap);
25  fprintf(stderr, "\n");
26  va_end(ap);
27 
28 #endif /* DEBUG */
29 }
30 
31 #ifdef DEBUG
32 
33 #define CHECKPOINT_LIST_SIZE 8
34 
35 typedef struct MemoryType {
36  const char *file;
37  unsigned int line;
38  size_t size;
39  char *pointer;
40  struct MemoryType *next;
41 } MemoryType;
42 
43 static MemoryType *allocations = NULL;
44 
45 static const char *checkpointFile[CHECKPOINT_LIST_SIZE];
46 static unsigned int checkpointLine[CHECKPOINT_LIST_SIZE];
47 static unsigned int checkpointOffset;
48 
50 void DEBUG_StartDebug(const char *file, unsigned int line)
51 {
52  unsigned int x;
53  Debug("%s[%u]: debug mode started", file, line);
54  checkpointOffset = 0;
55  for(x = 0; x < CHECKPOINT_LIST_SIZE; x++) {
56  checkpointFile[x] = NULL;
57  checkpointLine[x] = 0;
58  }
59 }
60 
62 void DEBUG_StopDebug(const char *file, unsigned int line)
63 {
64  Debug("%s[%u]: debug mode stopped", file, line);
65  if(allocations) {
66  MemoryType *mp;
67  unsigned int count = 0;
68  Debug("MEMORY: memory leaks follow");
69  for(mp = allocations; mp; mp = mp->next) {
70  Debug(" %u bytes in %s at line %u",
71  mp->size, mp->file, mp->line);
72  ++count;
73  }
74  if(count == 1) {
75  Debug("MEMORY: 1 memory leak");
76  } else {
77  Debug("MEMORY: %u memory leaks", count);
78  }
79  } else {
80  Debug("MEMORY: no memory leaks");
81  }
82 }
83 
85 void DEBUG_SetCheckpoint(const char *file, unsigned int line)
86 {
87  checkpointFile[checkpointOffset] = file;
88  checkpointLine[checkpointOffset] = line;
89  checkpointOffset = (checkpointOffset + 1) % CHECKPOINT_LIST_SIZE;
90 }
91 
93 void DEBUG_ShowCheckpoint(void)
94 {
95  unsigned int x, offset;
96  Debug("CHECKPOINT LIST (oldest)");
97  offset = checkpointOffset;
98  for(x = 0; x < CHECKPOINT_LIST_SIZE; x++) {
99  if(checkpointFile[offset]) {
100  Debug(" %s[%u]", checkpointFile[offset], checkpointLine[offset]);
101  }
102  offset = (offset + 1) % CHECKPOINT_LIST_SIZE;
103  }
104  Debug("END OF CHECKPOINT LIST (most recent)");
105 }
106 
108 void *DEBUG_Allocate(size_t size, const char *file, unsigned int line)
109 {
110  MemoryType *mp;
111  mp = (MemoryType*)malloc(sizeof(MemoryType));
112  Assert(mp);
113  mp->file = file;
114  mp->line = line;
115  mp->size = size;
116  mp->pointer = malloc(size + sizeof(char) + 8);
117  if(!mp->pointer) {
118  Debug("MEMORY: %s[%u]: Memory allocation failed (%d bytes)",
119  file, line, (int)size);
120  Assert(0);
121  }
122 
123  /* Make uninitialized accesses easy to find. */
124  memset(mp->pointer, 85, size);
125 
126  /* Canary value for buffer underflow/overflow checking. */
127  mp->pointer[7] = 42;
128  mp->pointer[size + 8] = 42;
129 
130  mp->next = allocations;
131  allocations = mp;
132  return mp->pointer + 8;
133 }
134 
136 void *DEBUG_Reallocate(void *ptr, size_t size,
137  const char *file,
138  unsigned int line)
139 {
140  MemoryType *mp;
141  if(!ptr) {
142  Debug("MEMORY: %s[%u]: Attempt to reallocate NULL pointer. "
143  "Calling Allocate...", file, line);
144  return DEBUG_Allocate(size, file, line);
145  } else {
146  char *cptr = (char*)ptr - 8;
147  for(mp = allocations; mp; mp = mp->next) {
148  if(mp->pointer == cptr) {
149  if(cptr[mp->size + 8] != 42) {
150  Debug("MEMORY: %s[%u]: The canary is dead (overflow).",
151  file, line);
152  }
153  if(cptr[7] != 42) {
154  Debug("MEMORY: %s[%u]: The canary is dead (underflow).",
155  file, line);
156  }
157  mp->file = file;
158  mp->line = line;
159  mp->size = size;
160  mp->pointer = realloc(cptr, size + sizeof(char) + 8);
161  if(!mp->pointer) {
162  Debug("MEMORY: %s[%u]: Failed to reallocate %d bytes.",
163  file, line, (int)size);
164  Assert(0);
165  }
166  mp->pointer[7] = 42;
167  mp->pointer[size + 8] = 42;
168  return mp->pointer + 8;
169  }
170  }
171 
172  Debug("MEMORY: %s[%u]: Attempt to reallocate unallocated pointer",
173  file, line);
174  mp = malloc(sizeof(MemoryType));
175  Assert(mp);
176  mp->file = file;
177  mp->line = line;
178  mp->size = size;
179  mp->pointer = malloc(size + sizeof(char) + 8);
180  if(!mp->pointer) {
181  Debug("MEMORY: %s[%u]: Failed to reallocate %d bytes.",
182  file, line, (int)size);
183  Assert(0);
184  }
185  memset(mp->pointer, 85, size);
186  mp->pointer[7] = 42;
187  mp->pointer[size + 8] = 42;
188  mp->next = allocations;
189  allocations = mp;
190  return mp->pointer + 8;
191  }
192 }
193 
195 void DEBUG_Release(void **ptr, const char *file, unsigned int line)
196 {
197  MemoryType *mp, *last;
198  if(!ptr) {
199  Debug("MEMORY: %s[%u]: Invalid attempt to release", file, line);
200  } else if(!*ptr) {
201  Debug("MEMORY: %s[%u]: Attempt to delete NULL pointer",
202  file, line);
203  } else {
204  char *cptr = (char*)*ptr - 8;
205  last = NULL;
206  for(mp = allocations; mp; mp = mp->next) {
207  if(mp->pointer == cptr) {
208  if(last) {
209  last->next = mp->next;
210  } else {
211  allocations = mp->next;
212  }
213 
214  if(cptr[mp->size + 8] != 42) {
215  Debug("MEMORY: %s[%u]: The canary is dead (overflow).",
216  file, line);
217  }
218  if(cptr[7] != 42) {
219  Debug("MEMORY: %s[%u]: The canary is dead (underflow).",
220  file, line);
221  }
222 
223  memset(cptr, 0xFF, mp->size + 8 + sizeof(char));
224  free(mp);
225  free(cptr);
226  *ptr = NULL;
227  return;
228  }
229  last = mp;
230  }
231  Debug("MEMORY: %s[%u]: Attempt to delete unallocated pointer",
232  file, line);
233  free(*ptr);
234 
235  /* This address should cause a segfault or bus error. */
236  *ptr = (void*)1;
237 
238  }
239 }
240 
241 #undef CHECKPOINT_LIST_SIZE
242 
243 #endif
244 

joewing.net / Projects / JWM