1 |
/* Memory management routines. |
2 |
* Leak checking based on code by Kelmar (2001/1/13). |
3 |
* |
4 |
* IRC Services is copyright (c) 1996-2009 Andrew Church. |
5 |
* E-mail: <achurch@achurch.org> |
6 |
* Parts written by Andrew Kempe and others. |
7 |
* This program is free but copyrighted software; see the file GPL.txt for |
8 |
* details. |
9 |
*/ |
10 |
|
11 |
#define NO_MEMREDEF |
12 |
#include "services.h" |
13 |
|
14 |
/*************************************************************************/ |
15 |
/*************************************************************************/ |
16 |
|
17 |
/* smalloc, scalloc, srealloc, sstrdup: |
18 |
* Versions of the memory allocation functions which will cause the |
19 |
* program to terminate with an "Out of memory" error if the memory |
20 |
* cannot be allocated. (Hence, the return value from these functions |
21 |
* is never NULL, except for smalloc()/scalloc() called with a size of |
22 |
* zero.) |
23 |
*/ |
24 |
|
25 |
#if MEMCHECKS |
26 |
# define FILELINE , const char *file, int line |
27 |
# define xmalloc(a) MCmalloc(a,file,line) |
28 |
# define xsmalloc(a) smalloc(a,file,line) |
29 |
# define xcalloc(a,b) MCcalloc(a,b,file,line) |
30 |
# define xrealloc(a,b) MCrealloc(a,b,file,line) |
31 |
# define xfree(a) MCfree(a,file,line) |
32 |
#else |
33 |
# define FILELINE /*nothing*/ |
34 |
# define xmalloc(a) malloc(a) |
35 |
# define xsmalloc(a) smalloc(a) |
36 |
# define xcalloc(a,b) calloc(a,b) |
37 |
# define xrealloc(a,b) realloc(a,b) |
38 |
# define xfree(a) free(a) |
39 |
#endif |
40 |
|
41 |
/*************************************************************************/ |
42 |
|
43 |
void *smalloc(long size FILELINE) |
44 |
{ |
45 |
void *buf; |
46 |
|
47 |
if (size == 0) |
48 |
return NULL; |
49 |
buf = xmalloc(size); |
50 |
if (buf == NULL) |
51 |
raise(SIGUSR1); |
52 |
return buf; |
53 |
} |
54 |
|
55 |
/*************************************************************************/ |
56 |
|
57 |
void *scalloc(long els, long elsize FILELINE) |
58 |
{ |
59 |
void *buf; |
60 |
|
61 |
if (elsize == 0 || els == 0) |
62 |
return NULL; |
63 |
buf = xcalloc(elsize, els); |
64 |
if (buf == NULL) |
65 |
raise(SIGUSR1); |
66 |
return buf; |
67 |
} |
68 |
|
69 |
/*************************************************************************/ |
70 |
|
71 |
void *srealloc(void *oldptr, long newsize FILELINE) |
72 |
{ |
73 |
void *buf; |
74 |
|
75 |
if (newsize == 0) { |
76 |
xfree(oldptr); |
77 |
return NULL; |
78 |
} |
79 |
buf = xrealloc(oldptr, newsize); |
80 |
if (buf == NULL) |
81 |
raise(SIGUSR1); |
82 |
return buf; |
83 |
} |
84 |
|
85 |
/*************************************************************************/ |
86 |
|
87 |
char *sstrdup(const char *s FILELINE) |
88 |
{ |
89 |
char *t = xsmalloc(strlen(s) + 1); |
90 |
strcpy(t, s); /* safe, obviously */ |
91 |
return t; |
92 |
} |
93 |
|
94 |
/*************************************************************************/ |
95 |
/************ Everything from here down is MEMCHECKS-related. ************/ |
96 |
/*************************************************************************/ |
97 |
|
98 |
#if MEMCHECKS |
99 |
|
100 |
/*************************************************************************/ |
101 |
|
102 |
static long allocated = 0; /* Amount of memory currently allocated */ |
103 |
static long runtime = 0; /* `allocated' value at init_memory() time */ |
104 |
|
105 |
# if SHOWALLOCS |
106 |
int showallocs = 1; /* Actually log allocations? */ |
107 |
# endif |
108 |
|
109 |
typedef struct _smemblock { |
110 |
long size; /* Size of this block */ |
111 |
int32 sig; /* Signature word: 0x5AFEC0DE */ |
112 |
} MemBlock; |
113 |
# define SIGNATURE 0x5AFEC0DE |
114 |
# define FREE_SIGNATURE 0xDEADBEEF /* Used for freed memory */ |
115 |
# define NEW_FILL 0xD017D017 /* New allocs are filled with this */ |
116 |
# define FREE_FILL 0xBEEF1E57 /* Freed memory is filled with this */ |
117 |
|
118 |
# define MEMBLOCK_TO_PTR(mb) ((void *)((char *)(mb) + sizeof(MemBlock))) |
119 |
# define PTR_TO_MEMBLOCK(ptr) ((MemBlock *)((char *)(ptr) - sizeof(MemBlock))) |
120 |
|
121 |
|
122 |
/*************************************************************************/ |
123 |
/*************************************************************************/ |
124 |
|
125 |
/* Leak-checking initialization and exit code. */ |
126 |
|
127 |
static void show_leaks(void) |
128 |
{ |
129 |
if (runtime >= 0 && (allocated - runtime) > 0) { |
130 |
log("SAFEMEM: There were %ld bytes leaked on exit!", |
131 |
(allocated - runtime)); |
132 |
} else { |
133 |
log("SAFEMEM: No memory leaks detected."); |
134 |
} |
135 |
} |
136 |
|
137 |
void init_memory(void) |
138 |
{ |
139 |
runtime = allocated; |
140 |
log("init_memory(): runtime = %ld", runtime); |
141 |
atexit(show_leaks); |
142 |
} |
143 |
|
144 |
/* Used to avoid memory-leak message from the parent process */ |
145 |
void uninit_memory(void) |
146 |
{ |
147 |
runtime = -1; |
148 |
} |
149 |
|
150 |
/*************************************************************************/ |
151 |
|
152 |
/* Helper to fill memory with a given 32-bit value. */ |
153 |
|
154 |
static inline void fill32(void *ptr, uint32 value, long size) |
155 |
{ |
156 |
register uint32 *ptr32 = ptr; |
157 |
register uint32 v = value; |
158 |
while (size >= 4) { |
159 |
*ptr32++ = v; |
160 |
size -= 4; |
161 |
} |
162 |
if (size > 0) |
163 |
memcpy(ptr32, &value, size); |
164 |
} |
165 |
|
166 |
/*************************************************************************/ |
167 |
/*************************************************************************/ |
168 |
|
169 |
/* Substitutes for malloc() and friends. memory.h redefines malloc(), etc. |
170 |
* to these functions if MEMCHECKS is defined. */ |
171 |
|
172 |
/*************************************************************************/ |
173 |
|
174 |
void *MCmalloc(long size, const char *file, int line) |
175 |
{ |
176 |
MemBlock *mb; |
177 |
void *data; |
178 |
|
179 |
if (size == 0) |
180 |
return NULL; |
181 |
mb = malloc(size + sizeof(MemBlock)); |
182 |
if (mb) { |
183 |
mb->size = size; |
184 |
mb->sig = SIGNATURE; |
185 |
data = MEMBLOCK_TO_PTR(mb); |
186 |
allocated += size; |
187 |
# if SHOWALLOCS |
188 |
if (showallocs) { |
189 |
log("smalloc(): Allocated %ld bytes at %p (%s:%d)", |
190 |
size, data, file, line); |
191 |
} |
192 |
# endif |
193 |
fill32(data, NEW_FILL, size); |
194 |
return data; |
195 |
} else { |
196 |
# if SHOWALLOCS |
197 |
if (showallocs) { |
198 |
log("mcalloc(): Unable to allocate %ld bytes (%s:%d)", |
199 |
size, file, line); |
200 |
} |
201 |
# endif |
202 |
return NULL; |
203 |
} |
204 |
} |
205 |
|
206 |
/*************************************************************************/ |
207 |
|
208 |
void *MCcalloc(long els, long elsize, const char *file, int line) |
209 |
{ |
210 |
MemBlock *mb; |
211 |
void *data; |
212 |
|
213 |
if (elsize == 0 || els == 0) |
214 |
return NULL; |
215 |
mb = malloc(els*elsize + sizeof(MemBlock)); |
216 |
if (mb) { |
217 |
mb->size = elsize * els; |
218 |
mb->sig = SIGNATURE; |
219 |
data = MEMBLOCK_TO_PTR(mb); |
220 |
memset(data, 0, els*elsize); |
221 |
allocated += mb->size; |
222 |
# if SHOWALLOCS |
223 |
if (showallocs) { |
224 |
log("scalloc(): Allocated %ld bytes at %p (%s:%d)", |
225 |
els*elsize, data, file, line); |
226 |
} |
227 |
# endif |
228 |
return data; |
229 |
} else { |
230 |
# if SHOWALLOCS |
231 |
if (showallocs) { |
232 |
log("scalloc(): Unable to allocate %ld bytes (%s:%d)", |
233 |
els*elsize, file, line); |
234 |
} |
235 |
# endif |
236 |
return NULL; |
237 |
} |
238 |
} |
239 |
|
240 |
/*************************************************************************/ |
241 |
|
242 |
void *MCrealloc(void *oldptr, long newsize, const char *file, int line) |
243 |
{ |
244 |
MemBlock *newb, *oldb; |
245 |
long oldsize; |
246 |
void *data; |
247 |
|
248 |
if (newsize == 0) { |
249 |
MCfree(oldptr, file, line); |
250 |
return NULL; |
251 |
} |
252 |
if (oldptr == NULL) |
253 |
return MCmalloc(newsize, file, line); |
254 |
oldb = PTR_TO_MEMBLOCK(oldptr); |
255 |
if (oldb->sig != SIGNATURE) { |
256 |
fatal("Attempt to realloc() an invalid pointer (%p) (%s:%d)", |
257 |
oldptr, file, line); |
258 |
} |
259 |
oldsize = oldb->size; |
260 |
newb = realloc(oldb, newsize + sizeof(MemBlock)); |
261 |
if (newb) { |
262 |
newb->size = newsize; |
263 |
newb->sig = SIGNATURE; /* should already be set... */ |
264 |
data = MEMBLOCK_TO_PTR(newb); |
265 |
allocated += (newsize - oldsize); |
266 |
# if SHOWALLOCS |
267 |
if (showallocs) { |
268 |
log("srealloc(): Adjusted %ld bytes (%p) to %ld bytes (%p)" |
269 |
" (%s:%d)", oldsize, oldptr, newsize, data, file, line); |
270 |
} |
271 |
# endif |
272 |
return data; |
273 |
} else { |
274 |
# if SHOWALLOCS |
275 |
if (showallocs) { |
276 |
log("srealloc(): Unable to adjust %ld bytes (%p) to %ld bytes" |
277 |
" (%s:%d)", oldsize, oldptr, newsize, file, line); |
278 |
} |
279 |
# endif |
280 |
return NULL; |
281 |
} |
282 |
} |
283 |
|
284 |
/*************************************************************************/ |
285 |
|
286 |
void MCfree(void *ptr, const char *file, int line) |
287 |
{ |
288 |
MemBlock *mb; |
289 |
|
290 |
if (ptr == NULL) |
291 |
return; |
292 |
mb = PTR_TO_MEMBLOCK(ptr); |
293 |
if (mb->sig != SIGNATURE) { |
294 |
fatal("Attempt to free() an invalid pointer (%p) (%s:%d)", |
295 |
ptr, file, line); |
296 |
} |
297 |
allocated -= mb->size; |
298 |
# if SHOWALLOCS |
299 |
if (showallocs) { |
300 |
log("sfree(): Released %ld bytes at %p (%s:%d)", |
301 |
mb->size, ptr, file, line); |
302 |
} |
303 |
# endif |
304 |
mb->size = FREE_FILL; |
305 |
mb->sig = FREE_SIGNATURE; |
306 |
fill32(ptr, FREE_FILL, mb->size); |
307 |
free(mb); |
308 |
} |
309 |
|
310 |
/*************************************************************************/ |
311 |
|
312 |
char *MCstrdup(const char *s, const char *file, int line) |
313 |
{ |
314 |
char *t = MCmalloc(strlen(s) + 1, file, line); |
315 |
strcpy(t, s); /* safe, obviously */ |
316 |
return t; |
317 |
} |
318 |
|
319 |
/*************************************************************************/ |
320 |
|
321 |
#endif /* MEMCHECKS */ |
322 |
|
323 |
/* |
324 |
* Local variables: |
325 |
* c-file-style: "stroustrup" |
326 |
* c-file-offsets: ((case-label . *) (statement-case-intro . *)) |
327 |
* indent-tabs-mode: nil |
328 |
* End: |
329 |
* |
330 |
* vim: expandtab shiftwidth=4: |
331 |
*/ |