Linux环境定位C程序内存泄露以及非法访问的方法

网上有很多例子,这里主要依照工作中的使用来记录一下心得。通过搜索可以搜到mcheck、mtrace、valgrind等等各种方法。这里记录一下:

1 mcheck
具体可以搜《Linux系统下借助mcheck实现c/c++程序的堆内存异常检查》这篇文章,比较详细。我比较喜欢用其中的b、c两种:

b. 在makefile中使用-lmcheck来链接程序。优点:无需在源码中显式调用mcheck,且一定可以保证mcheck先于malloc被调用;缺点:程序需要重新编译。 c. 通过设置环境变量MALLOC_CHECK_实现:export MALLOC_CHECK_=0表示检测到的堆内存异常都被忽略;export MALLOC_CHECK_=1表示检测到异常时,向stderr打印相关信息,程序继续运行;export MALLOC_CHECK_=2表示检测到异常时,程序立即abort。定位堆内存问题时,推荐设置为2,这样可以在异常发生时及时保留最近的现场。优点:无需改代码,亦无需重新编译;缺点:需设置环境变量,无法打印出堆内存一致性状态,只是简单的abort进程。

其中b的方法,在实际应用中发现有时会导致进程大量占用内存,具体原因没有查出。
其中c的方法,需要注意进程不能以守护方式后台运行。

2 warp
具体可以搜索《使用__wrap_malloc查看内存使用》这篇文章。
相关代码:

// wrap.c
#include <stdio.h>
#include <stdlib.h>
void* __real_malloc(size_t size); // 只声明不定义__real_malloc
void* __wrap_malloc(size_t size) // 定义__wrap_malloc
{
    printf("__wrap_malloc called, size:%zd\n", size); // log输出
    return __real_malloc(size); // 通过__real_malloc调用真正的malloc
} 
// test.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
    char* c = (char*)malloc(sizeof(char)); // 调用malloc
    printf("c = %p\n", c);
    free(c); // 调用free,防止内存泄漏
    return 0;
}
gcc -c wrap.c test.c
gcc -Wl,--wrap,malloc -o test wrap.o test.o // 链接参数-Wl,--wrap,malloc

3 hook
参看 https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html

在实际项目中,用到的C进程是opensaf拉起来的,涉及到.so和多线程。通过编写实验函数,证明hook的方式,.so中以及子线程中也是有效的。

相关代码:

//test.c
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <malloc.h>
#include "test_so.h"


/* Prototypes for our hooks.  */
static void my_init_hook (void);
static void *my_malloc_hook (size_t, const void *);
static void my_free_hook (void*, const void *);
void *old_malloc_hook = NULL;
void *old_free_hook = NULL;



static void
my_init (void)
{
  old_malloc_hook = __malloc_hook;
  old_free_hook = __free_hook;
  __malloc_hook = my_malloc_hook;
  __free_hook = my_free_hook;
}

static void *
my_malloc_hook (size_t size, const void *caller)
{
  void *result;
  /* Restore all old hooks */
  __malloc_hook = old_malloc_hook;
  __free_hook = old_free_hook;
  /* Call recursively */
  result = malloc (size);
  /* Save underlying hooks */
  old_malloc_hook = __malloc_hook;
  old_free_hook = __free_hook;
  /* printf might call malloc, so protect it too. */
  printf ("malloc (%u) returns %p\n", (unsigned int) size, result);
  /* Restore our own hooks */
  __malloc_hook = my_malloc_hook;
  __free_hook = my_free_hook;
  return result;
}

static void
my_free_hook (void *ptr, const void *caller)
{
  /* Restore all old hooks */
  __malloc_hook = old_malloc_hook;
  __free_hook = old_free_hook;
  /* Call recursively */
  free (ptr);
  /* Save underlying hooks */
  old_malloc_hook = __malloc_hook;
  old_free_hook = __free_hook;
  /* printf might call free, so protect it too. */
  printf ("freed pointer %p\n", ptr);
  /* Restore our own hooks */
  __malloc_hook = my_malloc_hook;
  __free_hook = my_free_hook;
}

void thread(void)
{
    int *a = malloc(20);
    printf("thread malloc\n");
    free(a);
    test_so();
    return;
}


int main ()
{
    pthread_t id;

    pthread_create(&id, NULL, (void*)thread, NULL);
    my_init();
    int *b = malloc(30);
    free(b);
    pthread_join(id, NULL);
    return 0;
}

//test_so.h
void test_sa();
//test_so.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test_so.h"

void test_so()
{
  int *p = malloc(100);
  printf("test so malloc!\n");
  free(p);
  printf("test so free!\n");
  return;
}
//编译:
gcc test_so.c -fPIC -shared -o libtest.so
gcc test.c -L. -ltest -lpthread -o test
发布了54 篇原创文章 · 获赞 1 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/xingyeping/article/details/72828788