1 /*
2 ** a_alloc.c - Allocation routines that either succeeds or abort.
3 **
4 ** Copyright (c) 1997-2000 Peter Eriksson <pen@lysator.liu.se>
5 **
6 ** This program is free software; you can redistribute it and/or
7 ** modify it as you wish - as long as you don't claim that you wrote
8 ** it.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 */
14
15 #define PLIB_IN_ALLOC_C
16
17 #include "plib/config.h"
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <syslog.h>
22 #include <string.h>
23
24 #include "plib/safeio.h"
25 #include "plib/threads.h"
26
27 #include "plib/aalloc.h"
28
29 typedef struct aahdr
30 {
31 struct aahdr *prev;
32 struct aahdr *next;
33 char fun[64];
34 char what[64];
35 size_t size;
36 unsigned short dummy;
37 unsigned short magic;
38 } AAHDR;
39
40 #define AAHDR_MAGIC_1 0x1234
41 #define AAHDR_MAGIC_2 0x56
42
43
44 static pthread_mutex_t aa_mtx;
45 static AAHDR *top = NULL;
46 static int aa_debug = 0;
47
48 static inline int
aahdr_valid(AAHDR * ap)49 aahdr_valid(AAHDR *ap)
50 {
51 unsigned char *cp;
52
53
54 if (ap == NULL)
55 return 0;
56
57 if (ap->magic != AAHDR_MAGIC_1)
58 return 0;
59
60 cp = (unsigned char *) (ap+1);
61
62 if (cp[ap->size] != AAHDR_MAGIC_2)
63 {
64 syslog(LOG_ERR, "aalloc: Buffer overrun for object at %p\n", (ap+1));
65 return 0;
66 }
67
68 return 1;
69 }
70
71
72 void
a_dump(FILE * fp)73 a_dump(FILE *fp)
74 {
75 AAHDR *ap;
76 unsigned char *p;
77
78
79 fprintf(fp, "a_dump(): Start\n");
80
81 pthread_mutex_lock(&aa_mtx);
82
83 ap = top;
84 while (ap)
85 {
86 p = (unsigned char *) (ap+1);
87
88 fprintf(fp, "%08p: magic=%04x:%02x, size=%lu, function=%s, object=%s\n",
89 ap, ap->magic, p[ap->size], ap->size,
90 ap->fun ? ap->fun : "<null>",
91 ap->what ? ap->what : "<null>");
92
93 ap = ap->next;
94 }
95 pthread_mutex_unlock(&aa_mtx);
96
97 fprintf(fp, "a_dump(): Stop\n");
98 }
99
100
101 void
a_init(void)102 a_init(void)
103 {
104 aa_debug = (getenv("AA_DEBUG") != NULL);
105
106 top = NULL;
107 pthread_mutex_init(&aa_mtx, NULL);
108 }
109
110
111 /*
112 ** A "safe" malloc, that always succeeds (or logs an
113 ** error to syslog and then abort()'s.
114 */
115
116 static inline void *
safe_malloc(size_t size,const char * fun,const char * what)117 safe_malloc(size_t size,
118 const char *fun,
119 const char *what)
120 {
121 int rsize;
122 void *p;
123 AAHDR *ap;
124 unsigned char *cp;
125
126
127 if (aa_debug)
128 rsize = size + sizeof(AAHDR) + 1;
129 else
130 rsize = size;
131
132 p = malloc(rsize);
133 if (p == NULL)
134 {
135 syslog(LOG_ERR, "%s: %s: malloc(%lu - real=%lu): %m",
136 fun ? fun : "<unknown function>",
137 what ? what : "<unknown object>",
138 (unsigned long) size,
139 (unsigned long) rsize);
140
141 s_abort();
142 }
143
144 if (aa_debug)
145 {
146 ap = (AAHDR *) p;
147
148 pthread_mutex_lock(&aa_mtx);
149
150 ap->prev = NULL;
151 if (top)
152 top->prev = ap;
153 ap->next = top;
154 top = ap;
155
156 ap->size = size;
157 strlcpy(ap->fun, fun, sizeof(ap->fun));
158 strlcpy(ap->what, what, sizeof(ap->what));
159 ap->magic = AAHDR_MAGIC_1;
160
161 cp = (unsigned char *) (ap+1);
162 cp[size] = AAHDR_MAGIC_2;
163
164 p = (void *) cp;
165
166 pthread_mutex_unlock(&aa_mtx);
167 }
168
169 return p;
170 }
171
172
173
174 void *
a_malloc(size_t size,const char * what)175 a_malloc(size_t size, const char *what)
176 {
177 void *p;
178
179
180 p = safe_malloc(size, "a_malloc", what);
181 memset(p, 0, size);
182
183 return p;
184 }
185
186
187 void *
a_realloc(void * oldp,size_t nsize,const char * what)188 a_realloc(void *oldp, size_t nsize, const char *what)
189 {
190 void *p;
191
192
193 if (!oldp)
194 return safe_malloc(nsize, "a_realloc", what);
195
196 if (aa_debug)
197 {
198 AAHDR *ap;
199
200 ap = (AAHDR *) oldp;
201 --ap;
202
203 if (!aahdr_valid(ap))
204 {
205 syslog(LOG_ERR, "a_realloc: INVALID pointer");
206 s_abort();
207 }
208
209 p = safe_malloc(nsize, "a_realloc", what);
210 memcpy(p, oldp, ap->size > nsize ? nsize : ap->size);
211 a_free(oldp);
212
213 return p;
214 }
215
216 p = (void *) realloc(oldp, nsize);
217 if (p == NULL)
218 {
219 syslog(LOG_ERR, "a_realloc: %s: realloc(...,%lu): %m",
220 what ? what : "<unknown object>",
221 (unsigned long) nsize);
222 s_abort();
223 }
224
225 return p;
226 }
227
228
229 void
a_free(void * p)230 a_free(void *p)
231 {
232 AAHDR *ap;
233
234
235 if (p == NULL)
236 return;
237
238
239 if (aa_debug)
240 {
241 ap = (AAHDR *) p;
242 --ap;
243
244 if (!aahdr_valid(ap))
245 {
246 syslog(LOG_ERR, "a_free: INVALID pointer");
247 s_abort();
248 }
249
250 pthread_mutex_lock(&aa_mtx);
251 if (ap->prev)
252 ap->prev->next = ap->next;
253 if (ap->next)
254 ap->next->prev = ap->prev;
255 if (top == ap)
256 top = ap->next;
257 pthread_mutex_unlock(&aa_mtx);
258 }
259
260 free(p);
261 }
262
263
264 char *
a_strndup(const char * s,size_t len,const char * what)265 a_strndup(const char *s,
266 size_t len,
267 const char *what)
268 {
269 char *ns;
270
271
272 if (s == NULL)
273 return NULL;
274
275 ns = (char *) safe_malloc(len+1, "a_strndup", what);
276
277 memcpy(ns, s, len);
278 ns[len] = '\0';
279
280 return ns;
281 }
282
283
284 char *
a_strdup(const char * s,const char * what)285 a_strdup(const char *s,
286 const char *what)
287 {
288 char *ns;
289 int len;
290
291
292 if (s == NULL)
293 return NULL;
294
295 len = strlen(s);
296 ns = (char *) safe_malloc(len+1, "a_strdup", what);
297
298 memcpy(ns, s, len+1);
299
300 return ns;
301 }
302
303