No more manifest files
[yaz-moved-to-github.git] / src / xmalloc.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file xmalloc.c
7  * \brief Implements malloc interface.
8  */
9
10 #if HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <assert.h>
18
19 #include <yaz/log.h>
20 #include <yaz/xmalloc.h>
21
22 #ifndef TRACE_XMALLOC
23 #define TRACE_XMALLOC 1
24 #endif
25
26 /* treat any size >1/4 of max value of size_t to be an error */
27 #define MALLOC_SIZE_MAX ((size_t)(-1) / 4)
28
29 static int log_level = 0;
30 static int log_level_initialized = 0;
31
32 #if TRACE_XMALLOC > 1
33
34 static const unsigned char head[] = {88, 77, 66, 55, 44, 33, 22, 11};
35 static const unsigned char tail[] = {11, 22, 33, 44, 55, 66, 77, 88};
36 static const unsigned char freed[] = {11, 22, 33, 44, 55, 66, 77, 88};
37
38 struct dmalloc_info {
39     int len;
40     char file[16];
41     int line;
42     struct dmalloc_info *next;
43     struct dmalloc_info *prev;
44 };
45
46 struct dmalloc_info *dmalloc_list = 0;
47
48
49 void *xmalloc_d(size_t nbytes, const char *file, int line)
50 {
51     char *res;
52     struct dmalloc_info *dinfo;
53
54     if (!log_level_initialized)
55     {
56         log_level = yaz_log_module_level("malloc");
57         log_level_initialized = 1;
58     }
59
60     if (!(res = (char*) malloc(nbytes + sizeof(*dinfo)+16*sizeof(char))))
61         return 0;
62     dinfo = (struct dmalloc_info *) res;
63     strncpy(dinfo->file, file, sizeof(dinfo->file)-1);
64     dinfo->file[sizeof(dinfo->file)-1] = '\0';
65     dinfo->line = line;
66     dinfo->len = nbytes;
67
68     dinfo->prev = 0;
69     dinfo->next = dmalloc_list;
70     if (dinfo->next)
71         dinfo->next->prev = dinfo;
72     dmalloc_list = dinfo;
73
74     memcpy(res + sizeof(*dinfo), head, 8*sizeof(char));
75     res += sizeof(*dinfo) + 8*sizeof(char);
76     memcpy(res + nbytes, tail, 8*sizeof(char));
77     return res;
78 }
79
80 void xfree_d(void *ptr, const char *file, int line)
81 {
82     struct dmalloc_info *dinfo;
83
84     if (!ptr)
85         return;
86     dinfo = (struct dmalloc_info *)
87         ((char*)ptr - 8*sizeof(char) - sizeof(*dinfo));
88     if (memcmp(head, (char*) ptr - 8*sizeof(char), 8*sizeof(char)))
89     {
90         yaz_log(YLOG_FATAL, "xfree_d bad head, %s:%d, %p", file, line, ptr);
91         abort();
92     }
93     if (memcmp((char*) ptr + dinfo->len, tail, 8*sizeof(char)))
94     {
95         yaz_log(YLOG_FATAL, "xfree_d bad tail, %s:%d, %p", file, line, ptr);
96         abort();
97     }
98     if (dinfo->prev)
99         dinfo->prev->next = dinfo->next;
100     else
101         dmalloc_list = dinfo->next;
102     if (dinfo->next)
103         dinfo->next->prev = dinfo->prev;
104     memcpy((char*) ptr - 8*sizeof(char), freed, 8*sizeof(char));
105     free(dinfo);
106     return;
107 }
108
109 void *xrealloc_d(void *p, size_t nbytes, const char *file, int line)
110 {
111     struct dmalloc_info *dinfo;
112     char *ptr = (char*) p;
113     char *res;
114
115     if (!log_level_initialized)
116     {
117         log_level = yaz_log_module_level("malloc");
118         log_level_initialized = 1;
119     }
120
121     if (!ptr)
122     {
123         if (!nbytes)
124             return 0;
125         res = (char *) malloc(nbytes + sizeof(*dinfo) + 16*sizeof(char));
126     }
127     else
128     {
129         if (memcmp(head, ptr - 8*sizeof(char), 8*sizeof(char)))
130         {
131             yaz_log(YLOG_FATAL, "xrealloc_d bad head, %s:%d, %p",
132                     file, line, ptr);
133             abort();
134         }
135         dinfo = (struct dmalloc_info *) (ptr-8*sizeof(char) - sizeof(*dinfo));
136         if (memcmp(ptr + dinfo->len, tail, 8*sizeof(char)))
137         {
138             yaz_log(YLOG_FATAL, "xrealloc_d bad tail, %s:%d, %p",
139                     file, line, ptr);
140             abort();
141         }
142         if (dinfo->prev)
143             dinfo->prev->next = dinfo->next;
144         else
145             dmalloc_list = dinfo->next;
146         if (dinfo->next)
147             dinfo->next->prev = dinfo->prev;
148
149         if (!nbytes)
150         {
151             free(dinfo);
152             return 0;
153         }
154         res = (char *)
155             realloc(dinfo, nbytes + sizeof(*dinfo) + 16*sizeof(char));
156     }
157     if (!res)
158         return 0;
159     dinfo = (struct dmalloc_info *) res;
160     strncpy(dinfo->file, file, sizeof(dinfo->file)-1);
161     dinfo->file[sizeof(dinfo->file)-1] = '\0';
162     dinfo->line = line;
163     dinfo->len = nbytes;
164
165     dinfo->prev = 0;
166     dinfo->next = dmalloc_list;
167     if (dmalloc_list)
168         dmalloc_list->prev = dinfo;
169     dmalloc_list = dinfo;
170
171     memcpy(res + sizeof(*dinfo), head, 8*sizeof(char));
172     res += sizeof(*dinfo) + 8*sizeof(char);
173     memcpy(res + nbytes, tail, 8*sizeof(char));
174     return res;
175 }
176
177 void *xcalloc_d(size_t nmemb, size_t size, const char *file, int line)
178 {
179     char *res;
180     struct dmalloc_info *dinfo;
181     size_t nbytes = nmemb * size;
182
183     if (!log_level_initialized)
184     {
185         log_level = yaz_log_module_level("malloc");
186         log_level_initialized = 1;
187     }
188
189     if (!(res = (char*) calloc(1, nbytes+sizeof(*dinfo)+16*sizeof(char))))
190         return 0;
191     dinfo = (struct dmalloc_info *) res;
192     strncpy(dinfo->file, file, sizeof(dinfo->file)-1);
193     dinfo->file[sizeof(dinfo->file)-1] = '\0';
194     dinfo->line = line;
195     dinfo->len = nbytes;
196
197     dinfo->prev = 0;
198     dinfo->next = dmalloc_list;
199     if (dinfo->next)
200         dinfo->next->prev = dinfo;
201     dmalloc_list = dinfo;
202
203     memcpy(res + sizeof(*dinfo), head, 8*sizeof(char));
204     res += sizeof(*dinfo) + 8*sizeof(char);
205     memcpy(res + nbytes, tail, 8*sizeof(char));
206     return res;
207 }
208
209 void xmalloc_trav_d(const char *file, int line)
210 {
211     size_t size = 0;
212     struct dmalloc_info *dinfo = dmalloc_list;
213
214     if (!log_level_initialized)
215     {
216         log_level = yaz_log_module_level("malloc");
217         log_level_initialized = 1;
218     }
219
220     yaz_log(log_level, "malloc_trav %s:%d", file, line);
221     while (dinfo)
222     {
223         yaz_log(log_level, " %20s:%d p=%p size=%d", dinfo->file, dinfo->line,
224                 ((char*) dinfo)+sizeof(*dinfo)+8*sizeof(char), dinfo->len);
225         size += dinfo->len;
226         dinfo = dinfo->next;
227     }
228     yaz_log(log_level, "total bytes %ld", (long) size);
229 }
230
231 #else
232 /* TRACE_XMALLOC <= 1 */
233 #define xrealloc_d(o, x, f, l) realloc(o, x)
234 #define xmalloc_d(x, f, l) malloc(x)
235 #define xcalloc_d(x,y, f, l) calloc(x,y)
236 #define xfree_d(x, f, l) free(x)
237 #define xmalloc_trav_d(f, l)
238 #endif
239
240 void xmalloc_trav_f(const char *s, const char *file, int line)
241 {
242     if (!log_level_initialized)
243     {
244         log_level = yaz_log_module_level("malloc");
245         log_level_initialized = 1;
246     }
247
248     xmalloc_trav_d(file, line);
249 }
250
251 void xmalloc_fatal(size_t size)
252 {
253     assert(size < MALLOC_SIZE_MAX);
254     exit(1);
255 }
256
257 void *xrealloc_f(void *o, size_t size, const char *file, int line)
258 {
259     void *p = xrealloc_d(o, size, file, line);
260
261     if (!log_level_initialized)
262     {
263         log_level = yaz_log_module_level("malloc");
264         log_level_initialized = 1;
265     }
266
267     if (log_level)
268         yaz_log(log_level,
269                 "%s:%d: xrealloc(s=%ld) %p -> %p", file, line, (long) size, o, p);
270     if (!p)
271     {
272         yaz_log(YLOG_FATAL, "%s:%d: Out of memory, realloc(%ld bytes)",
273                 file, line, (long) size);
274         xmalloc_fatal(size);
275     }
276     return p;
277 }
278
279 void *xmalloc_f(size_t size, const char *file, int line)
280 {
281     void *p = xmalloc_d(size, file, line);
282
283     if (!log_level_initialized)
284     {
285         log_level = yaz_log_module_level("malloc");
286         log_level_initialized = 1;
287     }
288
289     if (log_level)
290         yaz_log(log_level, "%s:%d: xmalloc(s=%ld) %p", file, line,
291                 (long) size, p);
292
293     if (!p)
294     {
295         yaz_log(YLOG_FATAL, "%s:%d: Out of memory - malloc(%ld bytes)",
296                 file, line, (long) size);
297         xmalloc_fatal(size);
298     }
299     return p;
300 }
301
302 void *xcalloc_f(size_t nmemb, size_t size, const char *file, int line)
303 {
304     void *p = xcalloc_d(nmemb, size, file, line);
305     if (!log_level_initialized)
306     {
307         log_level = yaz_log_module_level("malloc");
308         log_level_initialized = 1;
309     }
310
311     if (log_level)
312         yaz_log(log_level, "%s:%d: xcalloc(s=%ld) %p", file, line,
313                 (long) size, p);
314
315     if (!p)
316     {
317         yaz_log(YLOG_FATAL, "%s:%d: Out of memory - calloc(%ld, %ld)",
318                 file, line, (long) nmemb, (long) size);
319         xmalloc_fatal(size);
320     }
321     return p;
322 }
323
324 char *xstrdup_f(const char *s, const char *file, int line)
325 {
326     char *p = (char *)xmalloc_d(strlen(s)+1, file, line);
327     if (!log_level_initialized)
328     {
329         log_level = yaz_log_module_level("malloc");
330         log_level_initialized = 1;
331     }
332
333     if (log_level)
334         yaz_log(log_level, "%s:%d: xstrdup(s=%ld) %p", file, line,
335                 (long) strlen(s)+1, p);
336
337     strcpy(p, s);
338     return p;
339 }
340
341 void xfree_f(void *p, const char *file, int line)
342 {
343     if (!p)
344         return ;
345     if (log_level)
346         yaz_log(log_level, "%s:%d: xfree %p", file, line, p);
347     xfree_d(p, file, line);
348 }
349
350 char *xstrndup_f(const char *s, size_t n, const char *file, int line)
351 {
352     size_t l = strlen(s);
353     if (l < n)
354         return xstrdup_f(s, file, line);
355     {
356         char *a = (char*) xmalloc_f(n+1, file, line);
357         memcpy(a, s, n);
358         a[n] = '\0';
359         return a;
360     }
361 }
362
363 /*
364  * Local variables:
365  * c-basic-offset: 4
366  * c-file-style: "Stroustrup"
367  * indent-tabs-mode: nil
368  * End:
369  * vim: shiftwidth=4 tabstop=8 expandtab
370  */
371