Renamed stacktrace to memtrace
[runtime.git] / lib / silcutil / stacktrace.c
diff --git a/lib/silcutil/stacktrace.c b/lib/silcutil/stacktrace.c
deleted file mode 100644 (file)
index 60d8f05..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
-
-  stacktrace.c
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 2002 - 2008 Pekka Riikonen
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; version 2 of the License.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-*/
-
-/* This file implements memory leak checker and basic memory corruption
-   and double free checker.  It is multi-thread safe.  It does the
-   following:
-
-   o Tracks all memory allocations and report any unfreed memory at the
-     end of the program with backtrace where the memory was allocated.
-
-   o Checks if a memory location has been freed already and abort the
-     program with the backtrace of the location of the double free.
-
-   o Checks if a given pointer has been allocated at all and abort the
-     program with the backtrace where the invalid free was given.
-
-   o Checks at the time of free if the memory was written out of bounds
-     (overflow) and abort with the backtrace of the free.  The backtrace
-     might not help to find the overflow but at least it is detected.
-     By setting SILC_MALLOC_DUMP the memory is dummped to help and see
-     what it contains.
-
-   o Can detect if the memory is read or written out of bounds (overflow)
-     and abort immediately the with the backtrace when the illegal access
-     occurs.  This can be enabled by using SILC_MALLOC_PROTECT.
-
-   The following environment variables can be used:
-
-   SILC_MALLOC_NO_FREE
-
-     When set to value 1, the program doesn't actually free any memory.
-     This provides more detailed information especially in case of double
-     free.  If the location of the double free cannot be located, by
-     setting this variable the program will show where the memory was
-     originally allocated and freed.
-
-   SILC_MALLOC_DUMP
-
-     When set to value 1, in case of fatal error, dumps the memory location,
-     if possible.  This can help see what the memory contains.
-
-   SILC_MALLOC_PROTECT
-
-     When set to value 1 each allocation will have an inaccesible memory
-     page following the allocated memory area.  This will detect if the
-     the memory is accessed (read or write) beyond its boundaries.  This
-     will help to identify the place where illegal memory access occurs.
-
-   To work correctly this of course expects that code uses SILC memory
-   allocation and access routines.
-
-*/
-
-#include "silcruntime.h"
-
-#ifdef SILC_STACKTRACE
-#include <execinfo.h>
-#include <signal.h>
-#include <malloc.h>
-#include <sys/mman.h>
-
-static void *st_blocks = NULL;
-static unsigned long st_blocks_count = 0;
-static unsigned long st_num_malloc = 0;
-static SilcBool dump = FALSE;
-static SilcBool no_free = FALSE;
-static SilcBool dump_mem = FALSE;
-static SilcUInt32 pg = 0;
-static SilcMutex lock = NULL;
-
-#ifdef SILC_DEBUG
-#define SILC_ST_DEPTH 15
-#else
-#define SILC_ST_DEPTH 8
-#endif /* SILC_DEBUG */
-
-/* Memory block with stack trace */
-typedef struct SilcStBlockStruct {
-  struct SilcStBlockStruct *next;
-  struct SilcStBlockStruct *prev;
-  void *stack[SILC_ST_DEPTH];  /* Stack trace */
-  const char *file;            /* Allocation file in program */
-  const char *free_file;       /* Free file in program */
-  SilcUInt32 size;             /* Allocated memory size */
-  SilcUInt16 line;             /* Allocation line in program */
-  SilcUInt16 free_line;                /* Free line in program */
-  SilcUInt16 depth;            /* Depth of stack trace */
-  SilcUInt16 dumpped;          /* Block is dumpped */
-  SilcUInt32 bound;            /* Top bound */
-} *SilcStBlock;
-
-#define SILC_ST_TOP_BOUND 0xfeed1977
-#define SILC_ST_BOTTOM_BOUND 0x9152beef
-#define SILC_ST_GET_SIZE(size) ((size + sizeof(struct SilcStBlockStruct) + 4))
-#define SILC_ST_GET_STACK(p) ((SilcStBlock)(((unsigned char *)p) -     \
-                           sizeof(struct SilcStBlockStruct)))
-#define SILC_ST_GET_PTR(p) (((unsigned char *)p) +             \
-                           sizeof(struct SilcStBlockStruct))
-#define SILC_ST_GET_BOUND(p, size) (SilcUInt32 *)(((unsigned char *)p) + \
-                                   SILC_ST_GET_SIZE(size) - 4)
-
-#define SILC_ST_ALIGN(bytes, align) (((bytes) + (align - 1)) & ~(align - 1))
-#define SILC_ST_GET_SIZE_ALIGN(size, align) \
-  SILC_ST_ALIGN(SILC_ST_GET_SIZE(size) - 4, align)
-#define SILC_ST_GET_PTR_ALIGN(stack, align)                              \
-  (((unsigned char *)stack) - (SILC_ST_GET_SIZE_ALIGN(stack->size, pg) -  \
-                              SILC_ST_GET_SIZE(stack->size)) - 4)
-#define SILC_ST_GET_STACK_ALIGN(p, size, align)                                    \
-  ((SilcStBlock)(((unsigned char *)p) + (SILC_ST_GET_SIZE_ALIGN(size, pg) - \
-                                        SILC_ST_GET_SIZE(size)) + 4))
-
-void silc_st_abort(SilcStBlock stack, const char *file, int line,
-                  char *fmt, ...)
-{
-  void *bt[SILC_ST_DEPTH];
-  SilcUInt32 *bound;
-  va_list va;
-  int btc;
-
-  va_start(va, fmt);
-  vfprintf(stderr, fmt, va);
-  va_end(va);
-
-  fprintf(stderr, "----- BACKTRACE -----\n%s:%d:\n", file, line);
-  btc = backtrace(bt, SILC_ST_DEPTH);
-  backtrace_symbols_fd(bt, btc, 2);
-
-  if (stack) {
-    fprintf(stderr, "----- MEMORY TRACE -----\n");
-    if (stack->free_file)
-      fprintf(stderr, "Freed at: %s:%d\n", stack->free_file,
-             stack->free_line);
-    fprintf(stderr, "Originally allocated at:\n");
-    fprintf(stderr, "%s:%d:\n", stack->file, stack->line);
-    backtrace_symbols_fd(stack->stack, stack->depth, 2);
-    fflush(stderr);
-
-    if (dump_mem) {
-      fprintf(stderr, "----- MEMORY HEADER -----\n");
-      fprintf(stderr, "Header length: %lu, total length %lu\n",
-             sizeof(struct SilcStBlockStruct), SILC_ST_GET_SIZE(stack->size));
-      silc_hexdump((void *)stack, sizeof(struct SilcStBlockStruct), stderr);
-      fflush(stderr);
-      fprintf(stderr, "Header bound is: %p\n",
-             SILC_32_TO_PTR(stack->bound));
-      if (stack->bound != SILC_ST_TOP_BOUND) {
-       fprintf(stderr, "Header bound should be: %p\n",
-               SILC_32_TO_PTR(SILC_ST_TOP_BOUND));
-        fprintf(stderr, "MEMORY IS CORRUPTED (UNDERFLOW)!\n");
-      }
-
-      fprintf(stderr, "----- USER MEMORY -----\n");
-      fprintf(stderr, "Length: %d\n", stack->size);
-      silc_hexdump(((unsigned char *)stack) +
-                   sizeof(struct SilcStBlockStruct), stack->size, stderr);
-      fflush(stderr);
-
-      fprintf(stderr, "----- MEMORY FOOTER -----\n");
-      bound = SILC_ST_GET_BOUND(stack, stack->size);
-      silc_hexdump((unsigned char *)bound, 4, stderr);
-      fprintf(stderr, "Footer bound is: %p\n", SILC_32_TO_PTR(*bound));
-      if (*bound != SILC_ST_BOTTOM_BOUND) {
-       fprintf(stderr, "Footer bound should be: %p\n",
-               SILC_32_TO_PTR(SILC_ST_BOTTOM_BOUND));
-        fprintf(stderr, "MEMORY IS CORRUPTED (OVERFLOW)!\n");
-      }
-    }
-  }
-
-  fflush(stderr);
-
-  abort();
-}
-
-void silc_st_sigsegv(int sig, siginfo_t *si, void *context)
-{
-  SilcStBlock orig, stack = (SilcStBlock)si->si_addr;
-
-  /* Make the page accessible again */
-  mprotect(si->si_addr, pg, PROT_READ | PROT_WRITE);
-
-  /* Get the original page from the violated page */
-  orig = (SilcStBlock)(((unsigned char *)si->si_addr) -
-                       SILC_ST_GET_SIZE_ALIGN(stack->size, pg));
-  stack = SILC_ST_GET_STACK_ALIGN(orig, stack->size, pg);
-
-  silc_st_abort(stack, __FILE__, __LINE__,
-               "SILC_MALLOC: access violation (overflow)\n");
-}
-
-void silc_st_stacktrace_init(void)
-{
-  const char *var;
-
-  atexit(silc_st_dump);
-  dump = TRUE;
-
-  var = silc_getenv("SILC_MALLOC_NO_FREE");
-  if (var && *var == '1')
-    no_free = TRUE;
-
-  var = silc_getenv("SILC_MALLOC_DUMP");
-  if (var && *var == '1')
-    dump_mem = TRUE;
-
-  var = silc_getenv("SILC_MALLOC_PROTECT");
-  if (var && *var == '1') {
-    struct sigaction sa;
-
-    sa.sa_flags = SA_SIGINFO;
-    sa.sa_sigaction = silc_st_sigsegv;
-    sigemptyset(&sa.sa_mask);
-    sigaction(SIGSEGV, &sa, NULL);
-
-#if defined(_SC_PAGESIZE)
-    pg = sysconf(_SC_PAGESIZE);
-#elif defined(_SC_PAGE_SIZE)
-    pg = sysconf(_SC_PAGE_SIZE);
-#else
-    pg = getpagesize();
-#endif /* _SC_PAGESIZE */
-  }
-
-  /* Linux libc malloc check */
-  silc_setenv("MALLOC_CHECK_", "3");
-
-  /* NetBSD malloc check */
-  silc_setenv("MALLOC_OPTIONS", "AJ");
-
-  silc_mutex_alloc(&lock);
-}
-
-void *silc_st_malloc(size_t size, const char *file, int line)
-{
-  SilcStBlock stack;
-
-  if (silc_unlikely(!dump))
-    silc_st_stacktrace_init();
-
-  if (pg) {
-    unsigned char *ptr;
-
-    if (posix_memalign((void *)&ptr, pg,
-                      SILC_ST_GET_SIZE_ALIGN(size, pg) + pg))
-      return NULL;
-
-    /* The inaccessible page too will include the allocation information
-       so that we can get it when access violation occurs in that page. */
-    stack = (SilcStBlock)(ptr + SILC_ST_GET_SIZE_ALIGN(size, pg));
-    stack->size = size;
-
-    /* Protect the page */
-    if (mprotect(stack, pg, PROT_NONE))
-      silc_st_abort(NULL, file, line, "SILC_MALLOC: mprotect() error: %s\n",
-                   errno == ENOMEM ? "Cannot allocate memory. \nYour program "
-                   "leaks memory, allocates too much or system \n"
-                   "is out of memory.  The SILC_MALLOC_PROTECT cannot "
-                   "be used." : strerror(errno));
-
-    /* Get the accessible page */
-    stack = SILC_ST_GET_STACK_ALIGN(ptr, size, pg);
-  } else {
-    stack = (SilcStBlock)malloc(SILC_ST_GET_SIZE(size));
-    if (!stack)
-      return NULL;
-  }
-
-  stack->dumpped = 0;
-  stack->file = file;
-  stack->free_file = NULL;
-  stack->line = line;
-  stack->size = size;
-  stack->bound = SILC_ST_TOP_BOUND;
-  stack->depth = backtrace(stack->stack, SILC_ST_DEPTH);
-
-  silc_mutex_lock(lock);
-
-  stack->next = st_blocks;
-  stack->prev = NULL;
-  if (st_blocks)
-    ((SilcStBlock)st_blocks)->prev = stack;
-  st_blocks = stack;
-  st_blocks_count++;
-  st_num_malloc++;
-
-  silc_mutex_unlock(lock);
-
-  if (!pg)
-    *SILC_ST_GET_BOUND(stack, size) = SILC_ST_BOTTOM_BOUND;
-
-  return SILC_ST_GET_PTR(stack);
-}
-
-void *silc_st_calloc(size_t items, size_t size, const char *file, int line)
-{
-  void *addr = (void *)silc_st_malloc(items * size, file, line);
-  if (addr)
-    memset(addr, 0, items * size);
-  return addr;
-}
-
-void *silc_st_realloc(void *ptr, size_t size, const char *file, int line)
-{
-  SilcStBlock stack;
-
-  if (!ptr)
-    return silc_st_malloc(size, file, line);
-
-  stack = SILC_ST_GET_STACK(ptr);
-  if (!pg && stack->size >= size) {
-    /* Must update footer when the size changes */
-    if (stack->size != size)
-      *SILC_ST_GET_BOUND(stack, size) = SILC_ST_BOTTOM_BOUND;
-
-    stack->size = size;
-    return ptr;
-  } else {
-    void *addr = (void *)silc_st_malloc(size, file, line);
-    if (addr) {
-      memcpy(addr, ptr, size > stack->size ? stack->size : size);
-      silc_st_free(ptr, file, line);
-    }
-    return addr;
-  }
-}
-
-void silc_st_free(void *ptr, const char *file, int line)
-{
-  SilcStBlock stack, s;
-
-  if (!ptr)
-    return;
-
-  /* Check for double free */
-  if (!memcmp((unsigned char *)ptr - sizeof(struct SilcStBlockStruct),
-             "\x47\x47\x47\x47", 4))
-    silc_st_abort(no_free ? ptr - sizeof(struct SilcStBlockStruct) : NULL,
-                 file, line, "SILC_MALLOC: double free: %p already freed\n",
-                 ptr - sizeof(struct SilcStBlockStruct));
-
-  stack = SILC_ST_GET_STACK(ptr);
-
-  silc_mutex_lock(lock);
-
-  /* Check if we have ever made this allocation */
-  for (s = st_blocks; s; s = s->next)
-    if (s == stack)
-      break;
-  if (s == NULL)
-    silc_st_abort(NULL, file, line,
-                 "SILC_MALLOC: %p was never allocated\n", stack);
-
-  if (!pg) {
-    /* Check for underflow */
-    if (stack->bound != SILC_ST_TOP_BOUND)
-      silc_st_abort(stack, file, line,
-                   "SILC_MALLOC: %p was written out of bounds (underflow)\n",
-                   stack);
-
-    /* Check for overflow */
-    if (*SILC_ST_GET_BOUND(stack, stack->size) != SILC_ST_BOTTOM_BOUND)
-      silc_st_abort(stack, file, line,
-                   "SILC_MALLOC: %p was written out of bounds (overflow)\n",
-                   stack);
-  }
-
-  if (stack->next)
-    stack->next->prev = stack->prev;
-  if (stack->prev)
-    stack->prev->next = stack->next;
-  else
-    st_blocks = stack->next;
-
-  st_blocks_count--;
-
-  silc_mutex_unlock(lock);
-
-  stack->free_file = file;
-  stack->free_line = line;
-
-  if (no_free) {
-    memset(stack, 0x47, 8);
-    return;
-  }
-
-  if (pg) {
-    ptr = SILC_ST_GET_PTR_ALIGN(stack, pg);
-    mprotect(ptr + SILC_ST_GET_SIZE_ALIGN(stack->size, pg), pg,
-            PROT_READ | PROT_WRITE);
-    memset(ptr, 0x47, SILC_ST_GET_SIZE_ALIGN(stack->size, pg));
-    free(ptr);
-  } else {
-    memset(stack, 0x47, SILC_ST_GET_SIZE(stack->size));
-    free(stack);
-  }
-}
-
-void *silc_st_memdup(const void *ptr, size_t size, const char *file, int line)
-{
-  unsigned char *addr = (unsigned char *)silc_st_malloc(size + 1, file, line);
-  if (addr) {
-    memcpy((void *)addr, ptr, size);
-    addr[size] = '\0';
-  }
-  return (void *)addr;
-}
-
-void *silc_st_strdup(const char *string, const char *file, int line)
-{
-  return silc_st_memdup(string, strlen(string), file, line);
-}
-
-/* Dumps the stack into file if there are leaks. */
-
-void silc_st_dump(void)
-{
-  SilcStBlock stack, s;
-  unsigned long leaks = 0, blocks, bytes;
-  FILE *fp = NULL;
-  char **syms, *cp;
-  int i;
-  SilcMutex l;
-
-  l = lock;
-  lock = NULL;
-  silc_mutex_free(l);
-
-  for (stack = st_blocks; stack; stack = stack->next) {
-    bytes = blocks = 0;
-
-    if (stack->dumpped)
-      continue;
-
-    leaks++;
-
-    if (!fp) {
-      fp = fopen("stacktrace.log", "wb");
-      if (!fp)
-       fp = stderr;
-    }
-
-    /* Get symbol names */
-    syms = backtrace_symbols(stack->stack, stack->depth);
-
-    /* Find number of leaks and bytes leaked for this leak */
-    for (s = stack; s; s = s->next) {
-      if (s->file == stack->file && s->line == stack->line &&
-         s->depth == stack->depth &&
-         !memcmp(s->stack, stack->stack,
-                 (s->depth * sizeof(stack->stack[0])))) {
-       blocks++;
-       bytes += s->size;
-       s->dumpped = 1;
-      }
-    }
-
-    if (blocks) {
-      fprintf(fp, "<leak>%s:%d: #blocks=%lu, bytes=%lu\n",
-             stack->file, stack->line, blocks, bytes);
-      for (i = 0; i < stack->depth; i++) {
-       if (syms) {
-         cp = syms[i];
-         if (strchr(cp, '('))
-           cp = strchr(cp, '(') + 1;
-         else if (strchr(cp, ' '))
-           cp = strchr(cp, ' ') + 1;
-         if (strchr(cp, ')'))
-           *strchr(cp, ')') = ' ';
-         fprintf(fp, "\t%s\n", cp);
-       } else {
-         fprintf(fp, "\tpc=%p\n", stack->stack[i]);
-       }
-      }
-      fprintf(fp, "\n");
-      free(syms);
-    }
-  }
-
-  if (!leaks) {
-    fprintf(stderr, "\nNo memory leaks\n");
-  } else {
-    fprintf(stderr,
-           "-----------------------------------------\n"
-           "-----------------------------------------\n"
-           " Memory leaks dumped to 'stacktrace.log'\n"
-           " Leaks: %lu leaks, %lu blocks\n"
-           "-----------------------------------------\n"
-           "-----------------------------------------\n",
-           leaks, st_blocks_count);
-    fprintf(stderr, "Number of allocations: %lu\n", st_num_malloc);
-  }
-
-  if (fp && fp != stderr)
-    fclose(fp);
-}
-
-#endif /* SILC_STACKTRACE */