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;