目录
背景
之前在做项目过程中,用Lsan定位 memleak backtrace的时候出现 <unknown module>的情况,这个时候就不能用找到对应的 symbols so,从而用 llvm-addr2line去解析对应的代码行数。不方便找到对应的泄露点。
复现问题
泄漏发生在编译所需动态库中
泄漏发生在编译所需动态库中,这种情况可以直接编译后运行就能发现,测试代码如下。
// myadd.h
extern "C" int add(int a, int b);
//myadd.cpp
#include "myadd.h"
extern "C" int add(int a, int b)
{
int* p = new int(); // 内存泄漏的位置
return a + b;
}
// test.cpp
/*
#include "myadd.h"
#include <dlfcn.h>
#include <iostream>
typedef int (*FUNC)(int a,int b);
int main() {
void* handle = dlopen("./libmyadd.so", RTLD_LAZY);
FUNC myadd = (FUNC)dlsym(handle,"add");
int nVal = 0;
std::cin >> nVal;
std::cout << "519 + 1 = " << myadd(519, 1) << ", input:" << nVal << std::endl;
dlclose(handle);
return 0;
}
*/
#include "myadd.h"
#include <iostream>
int main()
{
std::cout << "519 + 1 = " << add(519, 1) << std::endl;
return 0;
}
编译运行、输出:
g++ -shared -fPIC -o libmyadd.so myadd.cpp
g++ test.cpp -L. -lmyadd -o test -Wl,-rpath=. -fsanitize=leak
输出backtrace:
wj@wj:~/WORKING_DIRECTORY/Learning/asan_learning/unknow module$ ./test
519 + 1 = 520
=================================================================
==305684==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x7fdef1f203c1 in operator new(unsigned long) ../../../../src/libsanitizer/lsan/lsan_interceptors.cpp:229
#1 0x7fdef1f0c134 in add (libmyadd.so+0x1134)
#2 0x5560487c421a in main (/home/wj/WORKING_DIRECTORY/Learning/asan_learning/unknow module/test+0x121a)
#3 0x7fdef19f1082 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: LeakSanitizer: 4 byte(s) leaked in 1 allocation(s).
也可以直接显示出内存泄漏的位置,内存泄漏在 libmyadd.so
动态库中的 add
函数中
泄漏发生在自定义加载的动态库中
这种情况要想精确定位问题就麻烦一些了,下面是用来测试的代码。
// myadd.h
extern "C" int add(int a, int b);
//myadd.cpp
#include "myadd.h"
extern "C" int add(int a, int b)
{
int* p = new int(); // 内存泄漏的位置
return a + b;
}
// test.cpp
// test.cpp
#include "myadd.h"
#include <dlfcn.h>
#include <iostream>
typedef int (*FUNC)(int a,int b);
int main() {
void* handle = dlopen("./libmyadd.so", RTLD_LAZY);
FUNC myadd = (FUNC)dlsym(handle,"add");
int nVal = 0;
std::cin >> nVal;
std::cout << "519 + 1 = " << myadd(519, 1) << ", input:" << nVal << std::endl;
dlclose(handle);
return 0;
}
编译、运行、输出:
g++ -shared -fPIC -o libmyadd.so myadd.cpp -g
g++ test.cpp -ldl -o test -Wl,-rpath=. -g -fsanitize=leak
wj@wj:~/WORKING_DIRECTORY/Learning/asan_learning/unknow module$ ./test
618
519 + 1 = 520, input:618
=================================================================
==307055==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4 byte(s) in 1 object(s) allocated from:
#0 0x7f464c0ca3c1 in operator new(unsigned long) ../../../../src/libsanitizer/lsan/lsan_interceptors.cpp:229
#1 0x7f464bb1b134 (<unknown module>)
#2 0x555ef90ae2f0 in main /home/wj/WORKING_DIRECTORY/Learning/asan_learning/unknow module/test.cpp:16
#3 0x7f464bb9a082 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: LeakSanitizer: 4 byte(s) leaked in 1 allocation(s).
从上面的backtrace 来看,泄漏点发生在<unknown module>,这一行,但是定位不到具体的泄漏信息,就比较麻烦,找不到真正泄漏点,出现 unknown module 的这种情况还挺多 。
出现 unknow module的原因
当使用 dlopen
的方式加载的动态库时,产生的内存泄漏常显示为 (<unknown module>)
,那是因为 lsan 在程序退出时分析内存泄漏情况,而这时自定义加载的动态库往往已经手动调用 dlclose 关闭了,这时就会显示成 #1 0x7f464bb1b134 (<unknown module>) 的情况。
unknow module的解决方案
maps
针对于出现 (<unknown module>)
的这种情况,可以通过查