⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memleak.c

📁 一个可用在嵌入式上检查内存泄露的源代码工具
💻 C
字号:
/**************************************************************************   memleak.c: A simple module for debbuging memory leaks. ANSI C.   Copyright (c) 2005 Stanislav Maslovski <s_i_m@mail.ru>   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; either version 2 of the License, or   (at your option) any later version.   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.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   *************************************************************************   ===================   Theory of operation   ===================   The program simply allocates a header together with a piece of data.   The headers contain information about the calls and are organized in a   bidirectional list. The history of malloc() - free() calls is collected   in a separate place in a circular buffer.      ============   Limitations:   ============   I use size_t to store the block allocation sizes and the overall allocated   memory count. In ANSI C there is no type modifier for printing size_t values,   so they are printed by casting to unsigned long (or long).   Pointers are validated by simple linear search in the lists, do not expect it   to be the same fast as the library routines.   ==============   How to use it:   ==============   include memleak.h into all modules of your program you want to debug.   Place a call to dbg_init() somewhere in the beginning of execution.   Add calls to dbg_mem_stat() or dbg_heap_dump() or others (see below)   to any suspicious place of your code. You may use "keyword" argument   to the dumping functions to reduce the amount of the output.   ===============================   void dbg_init(int history_size)   ===============================   This initializes the debugger. history_size defines the maximum number of   stored headers of the freed data.   ========================   void dbg_zero_stat(void)   ========================   clears statistics.   =======================   dbg_catch_sigsegv(void)   =======================   triggers on SIGSEGV signal handler.   ==================================================   int dbg_check_addr(char *msg, void *addr, int opt)   ==================================================   checks for addr in the tables given by opt. opt can be CHK_FREED or   CHK_ALLOC or CHK_ALL; returns CHK_FREED, CHK_ALLOC, or 0 if not found.   Also prints debugging message to stderr, prefixed with msg.   =======================   void dbg_mem_stat(void)    =======================   This function prints call statistics to stderr. The location of the   call is printed at the beginning of the status line. The status line   looks like this:      file:line m:<num> c: <num> r:<num> f:<num> mem:<num>      where m, c, r, f count malloc(), calloc(), realloc(), and free() calls.   mem equals the total amount of requested and not yet freed memory (not   exactly the same as the amount of actually allocated physical memory).       =================================   void dbg_heap_dump(char *keyword)   =================================   This function prints a dump of the current heap state to stderr. Every   line of the dump corresponds to an allocated and not yet freed piece of   data. Use "keyword" to narrower the dump: keyword = "" => entire heap   is dumped, if not "", strstr() is used to select strings with keyword   in them.   ====================================   void dbg_history_dump(char *keyword)   ====================================   dumps history of malloc() - free() calls. keyword is the same as above.*/#include <stdlib.h>#include <stdio.h>#include <string.h>#include <signal.h>#define die(msg) (perror(msg), abort())char *dbg_file_name;int dbg_line_number;static size_t memory_cnt = 0;static int malloc_cnt = 0;static int calloc_cnt = 0;static int realloc_cnt = 0;static int free_cnt = 0;static unsigned history_length = 0;struct head{  struct head *addr;  size_t size;  char *file;  unsigned line;  /* two addresses took the same space as an address and an integer on many archs => usable */  union {    struct { struct head*prev, *next; } list;    struct { char *file; unsigned line; } free;  };};#define CHK_FREED 1#define CHK_ALLOC 2#define CHK_ALL (CHK_FREED | CHK_ALLOC)int dbg_check_addr(char *msg, void *ptr, int opt);void dbg_abort(char *msg);static struct head *first = NULL, *last = NULL;static struct head *hist_base = NULL, *histp = NULL;#define HLEN sizeof(struct head)static struct head *add(void *buf, size_t s){  struct head *p;  p = malloc(HLEN);  if(p)    {      p->addr = buf;      p->size = s;      p->file = dbg_file_name;      p->line = dbg_line_number;      p->list.prev = last;      p->list.next = NULL;      if(last)	last->list.next = p;      else	first = p;      last = p;      memory_cnt += s;    }  return p;}#define ADVANCE(p) {if(++(p) >= hist_base + history_length) (p) = hist_base;}static void del(struct head *p){  struct head *prev, *next;  prev = p->list.prev;  next = p->list.next;  if(prev)    prev->list.next = next;  else    first = next;  if(next)    next->list.prev = prev;  else    last = prev;  memory_cnt -= p->size;  /* update history */  if(history_length)    {      p->free.file = dbg_file_name;      p->free.line = dbg_line_number;      memcpy(histp, p, HLEN);      ADVANCE(histp);    }  free(p);}static void replace(struct head *p, void *buf, size_t s){  memory_cnt -= p->size;  p->addr = buf;  p->size = s;  p->file = dbg_file_name;  p->line = dbg_line_number;  memory_cnt += s;}void *dbg_malloc(size_t s){  void *buf;  malloc_cnt++;  buf = malloc(s);  if(buf)    {      if(add(buf, s))	return buf;      else	free(buf);    }  fprintf(stderr, "%s:%u: dbg_malloc: not enough memory\n", dbg_file_name, dbg_line_number);  return NULL;}void *dbg_calloc(size_t n, size_t s){  void *buf;  s *= n;  calloc_cnt++;  buf = malloc(s);  if(buf)    {      if(add(buf, s))	{	  /* standard calloc() sets memory to zero */	  memset(buf, 0, s);	  return buf;	}      else	free(buf);    }  fprintf(stderr, "%s:%u: dbg_calloc: not enough memory\n", dbg_file_name, dbg_line_number);  return NULL;}static struct head *find_in_heap(void *addr){  struct head *p;  /* start search from lately allocated blocks */   for(p = last; p; p = p->list.prev)    if(p->addr == addr) return p;  return NULL;}static struct head *find_in_hist(void *addr){  struct head *p;  int cnt;  if(history_length)    {      if(histp->addr)	{	  cnt = history_length;	  p = histp;	}      else	{	  cnt = histp - hist_base;	  p = hist_base;	}      while(cnt--)	{	  if(p->addr == addr) return p;	  ADVANCE(p);	}    }  return NULL;}void dbg_free(void *buf){  struct head *p;  free_cnt++;  if(buf)    if((p = find_in_heap(buf)))      {        del(p);        free(buf);      }    else	dbg_check_addr("dbg_free", buf, CHK_FREED);  else    fprintf(stderr, "%s:%u: dbg_free: NULL\n", dbg_file_name, dbg_line_number);}void *dbg_realloc(void *buf, size_t s){  struct head *p;  realloc_cnt++;  if(buf) /* when buf is NULL do malloc. counted twice as r and m */    if(s)  /* when s = 0 realloc() acts like free(). counted twice: as r and f */      if((p = find_in_heap(buf)))	{	  buf = realloc(buf, s);	  if(buf)	    {	      replace(p, buf, s);	      return buf;	    }	  else	    fprintf(stderr, "%s:%u: dbg_realloc: not enough memory\n",		    dbg_file_name, dbg_line_number);	}      else	dbg_check_addr("dbg_realloc", buf, CHK_FREED);    else      dbg_free(buf);  else    return dbg_malloc(s);  return NULL;}int dbg_check_addr(char *msg, void *addr, int opt){  struct head *p;  if(opt & CHK_ALLOC)    if((p = find_in_heap(addr)))      {	fprintf(stderr, "%s:%u: %s: allocated (alloc: %s:%u size: %lu)\n",		dbg_file_name, dbg_line_number, msg, p->file, p->line, (unsigned long)p->size);	return CHK_ALLOC;      }  if(opt & CHK_FREED)    if((p = find_in_hist(addr)))      {	fprintf(stderr, "%s:%u: %s: freed (alloc: %s:%u size: %lu free: %s:%u)\n",		dbg_file_name, dbg_line_number, msg, p->file, p->line,		(unsigned long)p->size, p->free.file, p->free.line);	return CHK_FREED;      }  if(opt) fprintf(stderr, "%s:%u: %s: unknown\n", dbg_file_name, dbg_line_number, msg);  return 0;}void dbg_mem_stat(void){  fprintf(stderr, "%s:%u: m: %d, c: %d, r: %d, f: %d, mem: %ld\n",	  dbg_file_name, dbg_line_number,	  malloc_cnt, calloc_cnt, realloc_cnt, free_cnt, (long)memory_cnt);}void dbg_heap_dump(char *key){  char buf[80];  struct head *p;  fprintf(stderr, "***** %s:%u: heap dump start\n", dbg_file_name, dbg_line_number);  p = first;  while(p)    {      snprintf(buf, 80, "(alloc: %s:%u size: %lu)\n", p->file, p->line, (unsigned long)p->size);      p = p->list.next;      if(strstr(buf, key)) fputs(buf, stderr);    }  fprintf(stderr, "***** %s:%u: heap dump end\n", dbg_file_name, dbg_line_number);}void dbg_history_dump(char *key){  int cnt;  char buf[80];  struct head *p;  if(history_length)    {      fprintf(stderr, "***** %s:%u: history dump start\n", dbg_file_name, dbg_line_number);      if(histp->addr)	{	  cnt = history_length;	  p = histp;	}      else	{	  cnt = histp - hist_base;	  p = hist_base;	}      while(cnt--)	{	  snprintf(buf, 80, "(alloc: %s:%u size: %lu free: %s:%u)\n",		  p->file, p->line, (unsigned long)p->size, p->free.file, p->free.line);	  ADVANCE(p);	  if(strstr(buf, key)) fputs(buf, stderr);	}      fprintf(stderr, "***** %s:%u: history dump end\n", dbg_file_name, dbg_line_number);    }}     void dbg_abort(char *msg){  fprintf(stderr, "+++++ %s: aborting.\n+++++ last call at %s:%u\n",	            msg, dbg_file_name, dbg_line_number);  dbg_mem_stat();  dbg_heap_dump("");  if(history_length) dbg_history_dump("");  abort();}void dbg_zero_stat(void){  memory_cnt = 0;  malloc_cnt = 0;  calloc_cnt = 0;  realloc_cnt = 0;  free_cnt = 0;}static void sigsegv_handler(int signal){  if(signal == SIGSEGV)      dbg_abort("catched SIGSEGV");}void dbg_catch_sigsegv(void){  signal(SIGSEGV, sigsegv_handler);}void dbg_init(int hist_len){  history_length = hist_len;  if(history_length)    {      histp = hist_base = calloc(history_length, HLEN);      if(hist_base == NULL) die("cannot allocate history buffer");    }}/*  end*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -