16469d7263dbb54c4f16013ed77180eea573b0de
[yaz-moved-to-github.git] / util / xmalloc.c
1 /*
2  * Copyright (C) 1994-2000, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: xmalloc.c,v $
7  * Revision 1.12  2001-09-24 21:51:56  adam
8  * New Z39.50 OID utilities: yaz_oidval_to_z3950oid, yaz_str_to_z3950oid
9  * and yaz_z3950oid_to_str.
10  *
11  * Revision 1.11  2000/02/29 13:44:55  adam
12  * Check for config.h (currently not generated).
13  *
14  * Revision 1.10  1999/11/30 13:47:12  adam
15  * Improved installation. Moved header files to include/yaz.
16  *
17  * Revision 1.9  1999/09/10 08:58:32  adam
18  * Set TRACE_XMALLOC to 1.
19  *
20  * Revision 1.8  1999/08/27 09:40:32  adam
21  * Renamed logf function to yaz_log. Removed VC++ project files.
22  *
23  * Revision 1.7  1999/07/13 13:24:53  adam
24  * Updated memory debugging memory allocatation routines.
25  *
26  * Revision 1.6  1998/02/11 11:53:36  adam
27  * Changed code so that it compiles as C++.
28  *
29  * Revision 1.5  1997/10/31 12:20:09  adam
30  * Improved memory debugging for xmalloc/nmem.c. References to NMEM
31  * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
32  * Bug fix: missing fclose in data1_read_espec1.
33  *
34  * Revision 1.4  1996/07/03 13:21:36  adam
35  * Function xfree_f checks for NULL pointer.
36  *
37  * Revision 1.3  1995/12/05  15:08:44  adam
38  * Fixed verbose of xrealloc.
39  *
40  * Revision 1.2  1995/12/05  11:08:37  adam
41  * More verbose malloc routines.
42  *
43  * Revision 1.1  1995/11/01  11:56:53  quinn
44  * Added Xmalloc.
45  *
46  * Revision 1.6  1995/10/16  14:03:11  quinn
47  * Changes to support element set names and espec1
48  *
49  * Revision 1.5  1995/09/04  12:34:06  adam
50  * Various cleanup. YAZ util used instead.
51  *
52  * Revision 1.4  1994/10/05  10:16:16  quinn
53  * Added xrealloc. Fixed bug in log.
54  *
55  * Revision 1.3  1994/09/26  16:31:37  adam
56  * Added xcalloc_f.
57  *
58  * Revision 1.2  1994/08/18  08:23:26  adam
59  * Res.c now use handles. xmalloc defines xstrdup.
60  *
61  * Revision 1.1  1994/08/17  13:37:54  adam
62  * xmalloc.c added to util.
63  *
64  */
65
66 #if HAVE_CONFIG_H
67 #include <config.h>
68 #endif
69
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73
74 #include <yaz/log.h>
75 #include <yaz/xmalloc.h>
76
77 #define TRACE_XMALLOC 2
78
79 #if TRACE_XMALLOC > 1
80
81 static const unsigned char head[] = {44, 33, 22, 11};
82 static const unsigned char tail[] = {11, 22, 33, 44};
83 static const unsigned char freed[] = {11, 22, 33, 44};
84
85 struct dmalloc_info {
86     int len;
87     char file[16];
88     int line;
89     struct dmalloc_info *next;
90     struct dmalloc_info *prev;
91 };
92
93 struct dmalloc_info *dmalloc_list = 0;
94
95 void *xmalloc_d(size_t nbytes, const char *file, int line)
96 {
97     char *res;
98     struct dmalloc_info *dinfo;
99     
100     if (!(res = (char*) malloc(nbytes + sizeof(*dinfo)+8*sizeof(char))))
101         return 0;
102     dinfo = (struct dmalloc_info *) res;
103     strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
104     dinfo->file[sizeof(dinfo->file)-1] = '\0';
105     dinfo->line = line;
106     dinfo->len = nbytes;
107     
108     dinfo->prev = 0;
109     dinfo->next = dmalloc_list;
110     if (dinfo->next)
111         dinfo->next->prev = dinfo;
112     dmalloc_list = dinfo;
113     
114     memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
115     res += sizeof(*dinfo) + 4*sizeof(char);
116     memcpy(res + nbytes, tail, 4*sizeof(char));
117     return res;
118 }
119
120 void xfree_d(void *ptr, const char *file, int line)
121 {
122     struct dmalloc_info *dinfo;
123
124     if (!ptr)
125         return;
126     dinfo = (struct dmalloc_info *)
127         ((char*)ptr - 4*sizeof(char) - sizeof(*dinfo));
128     if (memcmp(head, (char*) ptr - 4*sizeof(char), 4*sizeof(char)))
129     {
130         yaz_log(LOG_FATAL, "xfree_d bad head, %s:%d, %p", file, line, ptr);
131         abort();
132     }
133     if (memcmp((char*) ptr + dinfo->len, tail, 4*sizeof(char)))
134     {
135         yaz_log(LOG_FATAL, "xfree_d bad tail, %s:%d, %p", 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     memcpy ((char*) ptr - 4*sizeof(char), freed, 4*sizeof(char));
145     free(dinfo);
146     return;
147 }
148
149 void *xrealloc_d(void *p, size_t nbytes, const char *file, int line)
150 {
151     struct dmalloc_info *dinfo;
152     char *ptr = (char*) p;
153     char *res;
154     
155     if (!ptr)
156     {
157         if (!nbytes)
158             return 0;
159         res = (char *) malloc(nbytes + sizeof(*dinfo) + 8*sizeof(char));
160     }
161     else
162     {
163         if (memcmp(head, ptr - 4*sizeof(char), 4*sizeof(char)))
164         {
165             yaz_log(LOG_FATAL, "xrealloc_d bad head, %s:%d, %p",
166                     file, line, ptr);
167             abort();
168         }
169         dinfo = (struct dmalloc_info *) (ptr-4*sizeof(char) - sizeof(*dinfo));
170         if (memcmp(ptr + dinfo->len, tail, 4*sizeof(char)))
171         {
172             yaz_log(LOG_FATAL, "xrealloc_d bad tail, %s:%d, %p",
173                     file, line, ptr);
174             abort();
175         }
176         if (dinfo->prev)
177             dinfo->prev->next = dinfo->next;
178         else
179             dmalloc_list = dinfo->next;
180         if (dinfo->next)
181             dinfo->next->prev = dinfo->prev;
182         
183         if (!nbytes)
184         {
185             free (dinfo);
186             return 0;
187         }
188         res = (char *)
189             realloc(dinfo, nbytes + sizeof(*dinfo) + 8*sizeof(char));
190     }
191     if (!res)
192         return 0;
193     dinfo = (struct dmalloc_info *) res;
194     strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
195     dinfo->file[sizeof(dinfo->file)-1] = '\0';
196     dinfo->line = line;
197     dinfo->len = nbytes;
198
199     dinfo->prev = 0;
200     dinfo->next = dmalloc_list;
201     if (dmalloc_list)
202         dmalloc_list->prev = dinfo;
203     dmalloc_list = dinfo;
204     
205     memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
206     res += sizeof(*dinfo) + 4*sizeof(char);
207     memcpy(res + nbytes, tail, 4*sizeof(char));
208     return res;
209 }
210
211 void *xcalloc_d(size_t nmemb, size_t size, const char *file, int line)
212 {
213     char *res;
214     struct dmalloc_info *dinfo;
215     size_t nbytes = nmemb * size;
216     
217     if (!(res = (char*) calloc(1, nbytes+sizeof(*dinfo)+8*sizeof(char))))
218         return 0;
219     dinfo = (struct dmalloc_info *) res;
220     strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
221     dinfo->file[sizeof(dinfo->file)-1] = '\0';
222     dinfo->line = line;
223     dinfo->len = nbytes;
224     
225     dinfo->prev = 0;
226     dinfo->next = dmalloc_list;
227     if (dinfo->next)
228         dinfo->next->prev = dinfo;
229     dmalloc_list = dinfo;
230     
231     memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
232     res += sizeof(*dinfo) + 4*sizeof(char);
233     memcpy(res + nbytes, tail, 4*sizeof(char));
234     return res;
235 }
236
237 void xmalloc_trav_d(const char *file, int line)
238 {
239     size_t size = 0;
240     struct dmalloc_info *dinfo = dmalloc_list;
241     
242     yaz_log (LOG_LOG, "malloc_trav %s:%d", file, line);
243     while (dinfo)
244     {
245         yaz_log (LOG_LOG, " %20s:%d p=%p size=%d", dinfo->file, dinfo->line,
246               ((char*) dinfo)+sizeof(*dinfo)+4*sizeof(char), dinfo->len);
247         size += dinfo->len;
248         dinfo = dinfo->next;
249     }
250     yaz_log (LOG_LOG, "total bytes %ld", (long) size);
251 }
252
253 #else
254 /* TRACE_XMALLOC <= 1 */
255 #define xrealloc_d(o, x, f, l) realloc(o, x)
256 #define xmalloc_d(x, f, l) malloc(x)
257 #define xcalloc_d(x,y, f, l) calloc(x,y)
258 #define xfree_d(x, f, l) free(x)
259 #define xmalloc_trav_d(f, l) 
260 #endif
261
262 void xmalloc_trav_f(const char *s, const char *file, int line)
263 {
264     xmalloc_trav_d(file, line);
265 }
266
267 void *xrealloc_f (void *o, size_t size, const char *file, int line)
268 {
269     void *p = xrealloc_d (o, size, file, line);
270
271 #if TRACE_XMALLOC
272     yaz_log (LOG_DEBUG,
273             "%s:%d: xrealloc(s=%d) %p -> %p", file, line, size, o, p);
274 #endif
275     if (!p)
276     {
277         yaz_log (LOG_FATAL|LOG_ERRNO, "Out of memory, realloc (%d bytes)",
278                  size);
279         exit(1);
280     }
281     return p;
282 }
283
284 void *xmalloc_f (size_t size, const char *file, int line)
285 {
286     void *p = xmalloc_d (size, file, line);
287     
288 #if TRACE_XMALLOC
289     yaz_log (LOG_DEBUG, "%s:%d: xmalloc(s=%d) %p", file, line, size, p);
290 #endif
291     if (!p)
292     {
293         yaz_log (LOG_FATAL, "Out of memory - malloc (%d bytes)", size);
294         exit (1);
295     }
296     return p;
297 }
298
299 void *xcalloc_f (size_t nmemb, size_t size, const char *file, int line)
300 {
301     void *p = xcalloc_d (nmemb, size, file, line);
302 #if TRACE_XMALLOC
303     yaz_log (LOG_DEBUG, "%s:%d: xcalloc(s=%d) %p", file, line, size, p);
304 #endif
305     if (!p)
306     {
307         yaz_log (LOG_FATAL, "Out of memory - calloc (%d, %d)", nmemb, size);
308         exit (1);
309     }
310     return p;
311 }
312
313 char *xstrdup_f (const char *s, const char *file, int line)
314 {
315     char *p = (char *)xmalloc_d (strlen(s)+1, file, line);
316 #if TRACE_XMALLOC
317     yaz_log (LOG_DEBUG, "%s:%d: xstrdup(s=%d) %p", file, line, strlen(s)+1, p);
318 #endif
319     strcpy (p, s);
320     return p;
321 }
322
323 void xfree_f(void *p, const char *file, int line)
324 {
325     if (!p)
326         return ;
327 #if TRACE_XMALLOC
328     if (p)
329         yaz_log (LOG_DEBUG, "%s:%d: xfree %p", file, line, p);
330 #endif
331     xfree_d(p, file, line);
332 }