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

📄 yamd.c

📁 很好用的内存泄漏检测工具。要配合linux的gcc使用,安装后将你的编译器gcc命令换成yamd-gcc就行了
💻 C
📖 第 1 页 / 共 4 页
字号:
  return (addr)p;}#if 0 /* Currently we never free memory.  Sad, but true. */static voidfree_pages(void *p, size_t npages){  if (remap_pages(p, npages) == 0)    REAL(free)(p);}#endif/* Utility functions *//* `mem_fill': Fill `dest_size' bytes of `dest' with repeating   sequences of the `src_size' bytes from `src', aligned to `src_size'   boundary. */static void mem_fill(uchar *dest, size_t dest_size, const uchar *src, size_t src_size){  size_t di;  size_t si;  si = di = 0;  while (di < dest_size)    {      while (si < src_size && di < dest_size)	dest[di++] = src[si++];      /* Start si over again. */      si = 0;    }}static size_t big_magic_size = 0;static uchar *big_magic = NULL; /* Filled on startup with as much magic			    as we need. */static inline voidmaybe_grow_big_magic(size_t new){  if (new > big_magic_size)    {      NO_CATCH();      big_magic = REAL(realloc)(big_magic, new);      OK_CATCH();      /* What to do if it runs out? */      if (!big_magic)	{	  log_event(LOG_ERR, "Out of memory for internal YAMD stuff");	  die();	}      mem_fill(big_magic, new, magic, sizeof(magic));    }}/* Compares blocks b1 and b2.  Returns offset by which they differ,   or -1 if the first n bytes are the same. */static inline ssize_t memcmp_w(uchar *b1, uchar *b2, size_t n){  /* Some assembly might be useful here */  size_t i = 0;  while (i < n && b1[i] == b2[i]) i++;  if (i == n)    return -1;  else    return i;}static addr magic_check_range(addr start, addr end){  ssize_t v;  size_t sz = end - start;  maybe_grow_big_magic(sz);  v = memcmp_w((uchar *)start, big_magic, sz);  if (v < 0)    return 0;  else    return start + v;}static voidmagic_fill_range(addr start, addr end){  size_t sz = end - start;  maybe_grow_big_magic(sz);  memcpy((void *)start, big_magic, sz);}#ifdef COMPLETE_MAGICstatic voidmagic_fill_block(block *b){  magic_fill_range((addr )b->block_addr + PGSZ, (addr )b->user_addr);  magic_fill_range((addr )b->user_addr + b->user_size, (addr )b->suffix_addr);}#endif/* Block management. */#define for_each_block(p) for (p = all_blocks; p; p = p->all_next)#define for_each_block_by_alignment(p, head) \  for (p = head; p; p = p->alignment_next) /* Should return a valid index into hash[]. *//* We use this because the low-order bits probably aren't random, nor are   the highest.  Here we get the middle, then shift and xor. *//* #define HASH_FUNC(n) (((n) / PGSZ) % HASH_SIZE) */#define HASH_FUNC(n) ((((n) / PGSZ) ^ (((n) / PGSZ) >> 8)) % HASH_SIZE)static voidinsert_block(block *b){  /* Insert into the hash table. */  int h;  h = HASH_FUNC(b->user_addr);  b->hash_next = hash[h];  hash[h] = b;  /* And into the all_blocks list */  b->all_next = all_blocks;  all_blocks = b;  /* And into its alignment list */  if (HAS_DEFAULT_ALIGNMENT(b))    {      b->alignment_next = unaligned_blocks;      unaligned_blocks = b;    }  else    {      b->alignment_next = aligned_blocks;      aligned_blocks = b;    }}static block *find_block_by_user_addr(addr a){  block *p;  for (p = hash[HASH_FUNC(a)]; p; p = p->hash_next)    if (p->user_addr == a)      return p;  return NULL;}/* This need not be fast; it's only called in the event of an error. */static block *find_block_by_any_addr(addr a){  block *p;  for_each_block(p)    if ((a >= p->block_addr) && (a < (p->block_addr + p->block_size)))      return p;  return NULL;}#ifdef HASH_PROFILEstatic voidhash_profile(void){  double avg;  double variance = 0.0;  int i;  avg = ((double)n_allocations) / HASH_SIZE;  for (i = 0; i < HASH_SIZE; i++)    {      int j = 0;      block *p;      for (p = hash[i]; p; p = p->hash_next)	j++;      variance += (pow(((double)j) - avg, 2.0) / (double)HASH_SIZE);    }  log_printf("Average chain length = %f, std dev = %f\n",	  avg, sqrt(variance));}#endif      static const char *get_entry_name(unsigned by_who){  static char *table[] = {    [BY_NONE] "nobody",    [BY_MALLOC] "malloc",    [BY_FREE] "free",    [BY_REALLOC] "realloc",    [BY_MEMALIGN] "memalign",    [BY_ALLOCA] "alloca",    [BY_AUTO] "alloca auto-free",    [BY_LITE] "lite-mode allocator"  };  return table[by_who];}/* Logging */static voidlog_flush(void){  write(log_fd, log_buf, log_buf_pos);  log_buf_pos = 0;}static voidlog_vprintf(const char *fmt, va_list va){  /* This is not at all safe; I really wish we always had vsnprintf */  if (log_buf_pos + MAX_PRINTF >= LOG_BUF_SIZE)    log_flush();  log_buf_pos += vsprintf(log_buf + log_buf_pos, fmt, va);  if (log_buf_pos + 1 >= LOG_BUF_SIZE)    {      /* Not a good thing. */      static char msg[] = "YAMD: Log buffer overrun-- increase MAX_PRINTF" \	" and recompile\n";      write(2, msg, strlen(msg));      abort();    }}static voidlog_printf(const char *fmt, ...){  va_list va;  va_start(va, fmt);  log_vprintf(fmt, va);  va_end(va);}static voidlog_event(int level, const char *desc){  char *ls;  if (level >= min_log_level)    {      switch (level)	{	case LOG_INFO: ls = "INFO"; break;	case LOG_WARN: ls = "WARNING"; break;	case LOG_ERR: ls = "ERROR"; break;	default: ls = "uh oh, don't know this"; break;	}      log_detail(level, "\n%s: %s\n", ls, desc);    }}static voidlog_detail(int level, const char *fmt, ...){  va_list vl;  if (level >= min_log_level)    {      va_start(vl, fmt);      log_vprintf(fmt, vl);      va_end(vl);    }}/* Generate a traceback and store it in `tb'.  If `eip_on_stack' is 1,   `start_ebp' is a frame pointer somewhere below the caller at `start_eip'.   Otherwise, `start_eip' is not on the stack; the traceback will start   with it and continue with the function whose frame pointer is `start_ebp'.*//* Standard GCC stack frame looks like:   ...   Return address   Saved EBP  <-- EBP points here   Local vars...*/#ifdef __linux__/* Bother.  There isn't really any good way to find out the limits   of the stack.  Guess we just have to trust the luser to have   compiled without -fomit-frame-pointer and not scrogged the stack... */#define STACK_ADDR_OK(a) ((a) != 0)#endif#ifdef __DJGPP__extern int djgpp_end asm ("end");#define STACK_ADDR_OK(a) (((a) >= (addr)&djgpp_end) && \			  ((a) < (addr)__djgpp_selector_limit))#endif/* This code looks a bit suspicious with respect to GCC's new aliasing   rules, but I think it's okay.  We only dereference pointers of type   `addr *', so we aren't referring to the same object via pointers   of different types.  Anyone who disagrees, please let me know. */static voidgenerate_any_traceback(TRACEBACK tb, addr start_eip, addr start_ebp,		       int eip_on_stack){  /* Wow.  Here be lots of ugly typecasts. */  addr ebp;  addr last_ebp;  addr eip;  size_t i;    if (eip_on_stack)    {      last_ebp = 0;      ebp = start_ebp;      eip = 0;  /* In case we abort immediately */      /* The last test really needs to be done only once, but this	 is cleaner */      while (ebp > last_ebp && STACK_ADDR_OK(ebp))	{	  eip = *((addr *)ebp + 1);	  last_ebp = ebp;	  ebp = *(addr *)ebp;	  if (eip == start_eip)	    break;	}      if (eip != start_eip)	{	  /* We broke out because the frame address went wrong, or maybe	     we reached the top.  Assume start_eip is right, but don't	     go any farther than that. */	  tb[0] = start_eip;	  tb[1] = 0;	  return;	}    }  else    {      eip = start_eip;      ebp = start_ebp;    }    i = 0;  last_ebp = 0;  tb[i++] = eip; /* Log the first one */  /* The last test really needs to be done only once, but this     is cleaner */  while (i < MAX_TRACEBACK_LEVELS - 1 && ebp > last_ebp && STACK_ADDR_OK(ebp))    {      tb[i++] = *((addr *)ebp + 1);      last_ebp = ebp;      ebp = *(addr *)ebp;    }  tb[i] = 0;}/* The standard case, where we want a traceback of our callers */static voidgenerate_traceback(TRACEBACK tb, addr eip){  generate_any_traceback(tb, eip, (addr)__builtin_frame_address(0), 1);}static voiddump_traceback(int level, TRACEBACK tb){  size_t i;  log_detail(level, "BEGIN TRACEBACK\n"); /* to allow indentation */#ifdef HAVE_BACKTRACE_SYMBOLS  if (level >= min_log_level)    {      for (i = 0; tb[i] != 0; i++) ;      log_flush();      backtrace_symbols_fd((void **)tb, i, log_fd);    }#else  for (i = 0; tb[i] != 0; i++)    {      log_detail(level, "  " POINTER_FORMAT "\n", tb[i]);    }#endif  log_detail(level, "END TRACEBACK\n");}static voiddo_any_traceback(int level, addr eip, addr ebp, int eip_os){  TRACEBACK buf;  generate_any_traceback(buf, eip, ebp, eip_os);  dump_traceback(level, buf);}static voiddo_traceback(int level, addr eip){  TRACEBACK buf;  generate_traceback(buf, eip);  dump_traceback(level, buf);}static voiddescribe_block(int level, block *b){  log_detail(level, "Address " POINTER_FORMAT ", size %u\n", b->user_addr, b->user_size);  log_detail(level, "Allocated by %s ",	     get_entry_name(b->who_alloced));  if (b->who_alloced == BY_MEMALIGN)    log_detail(level, "(alignment %u) ", b->alignment);  log_detail(level, "at\n");  dump_traceback(level, b->where_alloced);  if (b->who_freed != BY_NONE)    {      if (b->who_freed == BY_AUTO)	log_detail(level, "Automatically freed\n");      else	{	  log_detail(level, "Freed by %s at\n",		     get_entry_name(b->who_freed));	  dump_traceback(level, b->where_freed);	}    }  if (b->who_alloced == BY_REALLOC)    {      if (b->realloc_backlink == BAD_POINTER)	{	  log_detail(level, "Realloced from bad pointer\n");	}      else if (b->realloc_backlink == NULL)	{	  log_detail(level, "Realloced from NULL\n");	}      else	{	  log_detail(level, "Realloced from block:\n");	  describe_block(level, b->realloc_backlink);	}    }}static voidhandle_bad_magic(block *b, addr where){  log_event(LOG_ERR, "Corrupted block");  log_detail(LOG_ERR, "Bad magic bytes at " POINTER_FORMAT ", part of this block:\n", where);  describe_block(LOG_ERR, b);  log_detail(LOG_ERR, "Address in question is at offset %d\n",	     where - b->user_addr);  if (die_on_corrupted)    {      log_detail(LOG_ERR, "Dumping core\n");      die();    }  if (repair_corrupted)    {      log_detail(LOG_ERR, "Fixing\n");      /* Leave it to check_block to actually fix it, so it can catch	 corruption at the other end first. */    }  else    {      log_detail(LOG_ERR, "Leaving as is\n");    }}static voidcheck_block(block *b){  addr badp;  addr s, e;  /* If check_front, we'd have nothing to do, so we'd better not     be called in that case. */  if (b->who_freed != BY_NONE)    return;  /* We can't touch this area */  if (b->who_alloced == BY_LITE)    return; /* we don't want to know */#ifdef COMPLETE_MAGIC      

⌨️ 快捷键说明

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