+#include <yaz/log.h>
+#include <yaz/xmalloc.h>
+
+#ifndef TRACE_XMALLOC
+#define TRACE_XMALLOC 1
+#endif
+
+#if TRACE_XMALLOC > 1
+
+static const unsigned char head[] = {44, 33, 22, 11};
+static const unsigned char tail[] = {11, 22, 33, 44};
+static const unsigned char freed[] = {11, 22, 33, 44};
+
+struct dmalloc_info {
+ int len;
+ char file[16];
+ int line;
+ struct dmalloc_info *next;
+ struct dmalloc_info *prev;
+};
+
+struct dmalloc_info *dmalloc_list = 0;
+
+void *xmalloc_d(size_t nbytes, const char *file, int line)
+{
+ char *res;
+ struct dmalloc_info *dinfo;
+
+ if (!(res = (char*) malloc(nbytes + sizeof(*dinfo)+8*sizeof(char))))
+ return 0;
+ dinfo = (struct dmalloc_info *) res;
+ strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
+ dinfo->file[sizeof(dinfo->file)-1] = '\0';
+ dinfo->line = line;
+ dinfo->len = nbytes;
+
+ dinfo->prev = 0;
+ dinfo->next = dmalloc_list;
+ if (dinfo->next)
+ dinfo->next->prev = dinfo;
+ dmalloc_list = dinfo;
+
+ memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
+ res += sizeof(*dinfo) + 4*sizeof(char);
+ memcpy(res + nbytes, tail, 4*sizeof(char));
+ return res;
+}
+
+void xfree_d(void *ptr, const char *file, int line)
+{
+ struct dmalloc_info *dinfo;
+
+ if (!ptr)
+ return;
+ dinfo = (struct dmalloc_info *)
+ ((char*)ptr - 4*sizeof(char) - sizeof(*dinfo));
+ if (memcmp(head, (char*) ptr - 4*sizeof(char), 4*sizeof(char)))
+ {
+ yaz_log(LOG_FATAL, "xfree_d bad head, %s:%d, %p", file, line, ptr);
+ abort();
+ }
+ if (memcmp((char*) ptr + dinfo->len, tail, 4*sizeof(char)))
+ {
+ yaz_log(LOG_FATAL, "xfree_d bad tail, %s:%d, %p", file, line, ptr);
+ abort();
+ }
+ if (dinfo->prev)
+ dinfo->prev->next = dinfo->next;
+ else
+ dmalloc_list = dinfo->next;
+ if (dinfo->next)
+ dinfo->next->prev = dinfo->prev;
+ memcpy ((char*) ptr - 4*sizeof(char), freed, 4*sizeof(char));
+ free(dinfo);
+ return;
+}
+
+void *xrealloc_d(void *p, size_t nbytes, const char *file, int line)
+{
+ struct dmalloc_info *dinfo;
+ char *ptr = (char*) p;
+ char *res;
+
+ if (!ptr)
+ {
+ if (!nbytes)
+ return 0;
+ res = (char *) malloc(nbytes + sizeof(*dinfo) + 8*sizeof(char));
+ }
+ else
+ {
+ if (memcmp(head, ptr - 4*sizeof(char), 4*sizeof(char)))
+ {
+ yaz_log(LOG_FATAL, "xrealloc_d bad head, %s:%d, %p",
+ file, line, ptr);
+ abort();
+ }
+ dinfo = (struct dmalloc_info *) (ptr-4*sizeof(char) - sizeof(*dinfo));
+ if (memcmp(ptr + dinfo->len, tail, 4*sizeof(char)))
+ {
+ yaz_log(LOG_FATAL, "xrealloc_d bad tail, %s:%d, %p",
+ file, line, ptr);
+ abort();
+ }
+ if (dinfo->prev)
+ dinfo->prev->next = dinfo->next;
+ else
+ dmalloc_list = dinfo->next;
+ if (dinfo->next)
+ dinfo->next->prev = dinfo->prev;
+
+ if (!nbytes)
+ {
+ free (dinfo);
+ return 0;
+ }
+ res = (char *)
+ realloc(dinfo, nbytes + sizeof(*dinfo) + 8*sizeof(char));
+ }
+ if (!res)
+ return 0;
+ dinfo = (struct dmalloc_info *) res;
+ strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
+ dinfo->file[sizeof(dinfo->file)-1] = '\0';
+ dinfo->line = line;
+ dinfo->len = nbytes;
+
+ dinfo->prev = 0;
+ dinfo->next = dmalloc_list;
+ if (dmalloc_list)
+ dmalloc_list->prev = dinfo;
+ dmalloc_list = dinfo;
+
+ memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
+ res += sizeof(*dinfo) + 4*sizeof(char);
+ memcpy(res + nbytes, tail, 4*sizeof(char));
+ return res;
+}
+
+void *xcalloc_d(size_t nmemb, size_t size, const char *file, int line)
+{
+ char *res;
+ struct dmalloc_info *dinfo;
+ size_t nbytes = nmemb * size;
+
+ if (!(res = (char*) calloc(1, nbytes+sizeof(*dinfo)+8*sizeof(char))))
+ return 0;
+ dinfo = (struct dmalloc_info *) res;
+ strncpy (dinfo->file, file, sizeof(dinfo->file)-1);
+ dinfo->file[sizeof(dinfo->file)-1] = '\0';
+ dinfo->line = line;
+ dinfo->len = nbytes;
+
+ dinfo->prev = 0;
+ dinfo->next = dmalloc_list;
+ if (dinfo->next)
+ dinfo->next->prev = dinfo;
+ dmalloc_list = dinfo;
+
+ memcpy(res + sizeof(*dinfo), head, 4*sizeof(char));
+ res += sizeof(*dinfo) + 4*sizeof(char);
+ memcpy(res + nbytes, tail, 4*sizeof(char));
+ return res;
+}
+
+void xmalloc_trav_d(const char *file, int line)
+{
+ size_t size = 0;
+ struct dmalloc_info *dinfo = dmalloc_list;
+
+ yaz_log (LOG_LOG, "malloc_trav %s:%d", file, line);
+ while (dinfo)
+ {
+ yaz_log (LOG_LOG, " %20s:%d p=%p size=%d", dinfo->file, dinfo->line,
+ ((char*) dinfo)+sizeof(*dinfo)+4*sizeof(char), dinfo->len);
+ size += dinfo->len;
+ dinfo = dinfo->next;
+ }
+ yaz_log (LOG_LOG, "total bytes %ld", (long) size);
+}