[Groonga-commit] groonga/groonga [master] add memory management debuging code.

Back to archive index

null+****@clear***** null+****@clear*****
2010年 9月 30日 (木) 15:55:29 JST


Kouhei Sutou	2010-09-30 06:55:29 +0000 (Thu, 30 Sep 2010)

  New Revision: b1393ec467a482cb1751844423db58b96c398659

  Log:
    add memory management debuging code.
    
    It is only enabled when --enable-memory-debug option is specified.

  Modified files:
    configure.ac
    lib/ctx.c
    lib/expr.c
    lib/ql.h

  Modified: configure.ac (+14 -0)
===================================================================
--- configure.ac    2010-09-30 05:39:16 +0000 (05bebbc)
+++ configure.ac    2010-09-30 06:55:29 +0000 (ca66250)
@@ -291,6 +291,20 @@ if test "x$enable_dynamic_malloc_change" = "xyes"; then
             [Define to 1 if you enable dynamic malloc change])
 fi
 
+# memory debug
+AC_MSG_CHECKING([whether debug memory management])
+AC_ARG_ENABLE(memory-debug,
+  [AS_HELP_STRING([--enable-memory-debug],
+    [debug memory management. [default=no]])],
+  ,
+  [enable_memory_debug="no"])
+AC_MSG_RESULT([$enable_memory_debug])
+
+if test "x$enable_memory_debug" = "xyes"; then
+  AC_DEFINE(ENABLE_MEMORY_DEBUG, [1],
+            [Define to 1 if you enable debuging memory management])
+fi
+
 # epoll/kqueue/poll/select check
 AC_CHECK_HEADER(sys/epoll.h, [
   AC_CHECK_FUNC(epoll_create, [

  Modified: lib/ctx.c (+86 -1)
===================================================================
--- lib/ctx.c    2010-09-30 05:39:16 +0000 (d4122ad)
+++ lib/ctx.c    2010-09-30 06:55:29 +0000 (b571f6f)
@@ -255,6 +255,9 @@ grn_ctx_impl_init(grn_ctx *ctx)
 #ifdef USE_DYNAMIC_MALLOC_CHANGE
   grn_ctx_impl_init_malloc(ctx);
 #endif
+#ifdef ENABLE_MEMORY_DEBUG
+  ctx->impl->alloc_info = NULL;
+#endif
   ctx->impl->encoding = ctx->encoding;
   ctx->impl->lifoseg = -1;
   ctx->impl->currseg = -1;
@@ -1879,6 +1882,79 @@ grn_strdup(grn_ctx *ctx, const char *string, const char* file, int line, const c
 }
 #endif
 
+#ifdef ENABLE_MEMORY_DEBUG
+inline static void
+grn_alloc_info_add(grn_ctx *ctx, void *address)
+{
+#  define N_TRACE_LEVEL 100
+  grn_alloc_info *new_alloc_info;
+  static void *trace[N_TRACE_LEVEL];
+  int i, n, rest;
+  char *backtrace_buffer;
+  char **symbols;
+
+  if (!ctx->impl) { return; }
+
+  new_alloc_info = malloc(sizeof(grn_alloc_info));
+  new_alloc_info->address = address;
+  new_alloc_info->freed = GRN_FALSE;
+  new_alloc_info->backtrace[0] = '\0';
+  backtrace_buffer = new_alloc_info->backtrace;
+  rest = sizeof(new_alloc_info->backtrace);
+
+  n = backtrace(trace, N_TRACE_LEVEL);
+  symbols = backtrace_symbols(trace, n);
+  if (symbols) {
+    for (i = 0; i < n; i++) {
+      int symbol_length;
+
+      symbol_length = strlen(symbols[i]);
+      if (symbol_length + 2 > rest) {
+        break;
+      }
+      memcpy(backtrace_buffer, symbols[i], symbol_length);
+      backtrace_buffer += symbol_length;
+      rest -= symbol_length;
+      backtrace_buffer[0] = '\n';
+      backtrace_buffer++;
+      rest--;
+      backtrace_buffer[0] = '\0';
+      rest--;
+    }
+    free(symbols);
+  }
+
+  new_alloc_info->next = ctx->impl->alloc_info;
+  ctx->impl->alloc_info = new_alloc_info;
+#  undef N_TRACE_LEVEL
+}
+
+inline static void
+grn_alloc_info_check(grn_ctx *ctx, void *address)
+{
+  grn_alloc_info *alloc_info;
+
+  if (!ctx->impl) { return; }
+
+  alloc_info = ctx->impl->alloc_info;
+  for (; alloc_info; alloc_info = alloc_info->next) {
+    if (alloc_info->address == address) {
+      if (alloc_info->freed) {
+        GRN_LOG(ctx, GRN_LOG_WARNING,
+                "double free: (%p):\n%s",
+                alloc_info->address, alloc_info->backtrace);
+      } else {
+        alloc_info->freed = GRN_TRUE;
+      }
+      return;
+    }
+  }
+}
+#else
+#  define grn_alloc_info_add(ctx, address)
+#  define grn_alloc_info_check(ctx, address)
+#endif
+
 void *
 grn_malloc_default(grn_ctx *ctx, size_t size, const char* file, int line, const char *func)
 {
@@ -1887,11 +1963,13 @@ grn_malloc_default(grn_ctx *ctx, size_t size, const char* file, int line, const
     void *res = malloc(size);
     if (res) {
       GRN_ADD_ALLOC_COUNT(1);
+      grn_alloc_info_add(ctx, res);
     } else {
       if (!(res = malloc(size))) {
         MERR("malloc fail (%d)=%p (%s:%d) <%d>", size, res, file, line, alloc_count);
       } else {
         GRN_ADD_ALLOC_COUNT(1);
+        grn_alloc_info_add(ctx, res);
       }
     }
     return res;
@@ -1906,11 +1984,13 @@ grn_calloc_default(grn_ctx *ctx, size_t size, const char* file, int line, const
     void *res = calloc(size, 1);
     if (res) {
       GRN_ADD_ALLOC_COUNT(1);
+      grn_alloc_info_add(ctx, res);
     } else {
       if (!(res = calloc(size, 1))) {
         MERR("calloc fail (%d)=%p (%s:%d) <%d>", size, res, file, line, alloc_count);
       } else {
         GRN_ADD_ALLOC_COUNT(1);
+        grn_alloc_info_add(ctx, res);
       }
     }
     return res;
@@ -1921,6 +2001,7 @@ void
 grn_free_default(grn_ctx *ctx, void *ptr, const char* file, int line, const char *func)
 {
   if (!ctx) { return; }
+  grn_alloc_info_check(ctx, ptr);
   {
     free(ptr);
     if (ptr) {
@@ -1943,9 +2024,13 @@ grn_realloc_default(grn_ctx *ctx, void *ptr, size_t size, const char* file, int
         return NULL;
       }
     }
-    if (!ptr) { GRN_ADD_ALLOC_COUNT(1); }
+    if (!ptr) {
+      GRN_ADD_ALLOC_COUNT(1);
+      grn_alloc_info_add(ctx, res);
+    }
   } else {
     if (!ptr) { return NULL; }
+    grn_alloc_info_check(ctx, ptr);
     GRN_ADD_ALLOC_COUNT(-1);
 #if defined __FreeBSD__
     free(ptr);

  Modified: lib/expr.c (+4 -0)
===================================================================
--- lib/expr.c    2010-09-30 05:39:16 +0000 (7b0ad5a)
+++ lib/expr.c    2010-09-30 06:55:29 +0000 (457ed83)
@@ -616,11 +616,15 @@ grn_expr_close(grn_ctx *ctx, grn_obj *expr)
     grn_obj *obj;
     GRN_PTR_POP(&e->objs, obj);
     if (obj) {
+#ifdef ENABLE_MEMORY_DEBUG
+      grn_obj_unlink(ctx, obj);
+#else
       if (obj->header.type) {
         grn_obj_unlink(ctx, obj);
       } else {
         GRN_LOG(ctx, GRN_LOG_WARNING, "GRN_VOID object is tried to be unlinked");
       }
+#endif
     } else { break; }
   }
   grn_obj_close(ctx, &e->objs);

  Modified: lib/ql.h (+16 -0)
===================================================================
--- lib/ql.h    2010-09-30 05:39:16 +0000 (f78fcd4)
+++ lib/ql.h    2010-09-30 06:55:29 +0000 (b3bac0f)
@@ -162,6 +162,17 @@ typedef struct {
 #define GRN_STACK_SIZE 1024
 #define GRN_CTX_N_SEGMENTS 512
 
+#ifdef ENABLE_MEMORY_DEBUG
+typedef struct _grn_alloc_info grn_alloc_info;
+struct _grn_alloc_info
+{
+  void *address;
+  int freed;
+  char backtrace[4096];
+  grn_alloc_info *next;
+};
+#endif
+
 struct _grn_ctx_impl {
   grn_encoding encoding;
 
@@ -179,6 +190,11 @@ struct _grn_ctx_impl {
   grn_strdup_func strdup_func;
 #endif
 
+#ifdef ENABLE_MEMORY_DEBUG
+  /* memory debug portion */
+  grn_alloc_info *alloc_info;
+#endif
+
   /* qe portion */
   grn_obj *stack[GRN_STACK_SIZE];
   uint32_t stack_curr;




Groonga-commit メーリングリストの案内
Back to archive index