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