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

来源:互联网 发布:面试测评软件系统 编辑:程序博客网 时间:2024/05/20 06:29

网上有很多例子,这里主要依照工作中的使用来记录一下心得。通过搜索可以搜到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_mallocvoid* __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.cgcc -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 voidmy_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 voidmy_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.hvoid 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.sogcc test.c -L. -ltest -lpthread -o test
原创粉丝点击