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