一 简述
android 的libc中有malloc_debug的hook调用,我们可以使用malloc_debug中的hook函数对内存分配进行跟踪加测。
malloc_debug主要包含的功能如下:
- 内存分配和释放跟踪,支持的函数如下:
malloc
free
calloc
realloc
posix_memalign
memalign
aligned_alloc
malloc_usable_size
2) 支持内存边界,可以在申请的内存头部和尾部添加guard,内存越界检查,use after free,内存崩溃检查等。
3) 调用栈跟踪和打印,跟踪内存分配的同时保存内存分配的调用栈,方便内存泄漏检查。
二 malloc_debug使用
1) 开启malloc_debug
adb shell setprop libc.debug.malloc.program
- 设置相关检测项
adb shell setprop libc.debug.malloc.options backtrace
3)重启应用程序
三) malloc_debug原理
libc在初始化时会调用MallocInitImpl判断属性来加载debug so,调用InitMallocFunctions替换掉Libc原生的内存分配和释放函数。
// Initializes memory allocation framework once per process.
static void MallocInitImpl(libc_globals* globals) {
char prop[PROP_VALUE_MAX];
char* options = prop;
MaybeInitGwpAsanFromLibc(globals);
// Prefer malloc debug since it existed first and is a more complete
// malloc interceptor than the hooks.
bool hook_installed = false;
if (CheckLoadMallocDebug(&options)) {
hook_installed = InstallHooks(globals, options, kDebugPrefix, kDebugSharedLib);
} else if (CheckLoadMallocHooks(&options)) {
hook_installed = InstallHooks(globals, options, kHooksPrefix, kHooksSharedLib);
}
if (!hook_installed) {
if (HeapprofdShouldLoad()) {
HeapprofdInstallHooksAtInit(globals);
}
} else {
// Record the fact that incompatible hooks are active, to skip any later
// heapprofd signal handler invocations.
HeapprofdRememberHookConflict();
}
}
除了内存分配和释放,常见如下:
"initialize",
"finalize",
"get_malloc_leak_info",
"free_malloc_leak_info",
"malloc_backtrace",
"write_malloc_leak_info",
比如在完成注册后,调用FinishInstallHooks,initialize,将finalize注册到process退出时。
四 malloc_debug option选项
1) 内存边界检查
front_guard[=SIZE_BYTES]Enables a small buffer placed before the allocated data.
rear_guard[=SIZE_BYTES] Enables a small buffer placed after the allocated data.
guard[=SIZE_BYTES] Enables both a front guard and a rear guard on all allocations.
主要原理是在分配内存的头部和尾部添加一段数据,作为边界,头部初始化为0xaa,尾部初始化为0xbb。
2)调用栈功能
backtrace[=MAX_FRAMES]
backtrace_enable_on_signal[=MAX_FRAMES]
backtrace_dump_on_exit
backtrace_dump_prefix
backtrace_full
设置保存的调用栈个数,在信号量或者退出时打印调用栈
3) malloc内存默认值
fill_on_alloc[=MAX_FILLED_BYTES] size will be set to 0xeb.
fill_on_free[=MAX_FILLED_BYTES] When an allocation is freed, fill it with 0xef.
fill[=MAX_FILLED_BYTES] This enables both the fill_on_alloc option and the fill_on_free option.
expand_alloc[=EXPAND_BYTES] Add an extra amount to allocate for every allocation.
- 释放内存存档
free_track[=ALLOCATION_COUNT] 默认值是100,最大值是16384
free_track_backtrace_num_frames[=MAX_FRAMES]
5)分配释放检测
leak_track 在进程退出时,执行finalize函数,打印当前分配的内存
record_allocs[=TOTAL_ENTRIES] 记录alloc操作,The default value is 8,000,000 and the maximum value this can be set to is 50,000,000.
record_allocs_file[=FILE_NAME] 设置record_allocs保存地址
verify_pointers free/malloc_usable_size/realloc 有效检查
abort_on_error When malloc debug detects an error, abort after sending the error log message.内存泄漏检测不在此处,只在进程退出时检测
6) verbose 开启debug info log,如果要看更多的信息,建议开启此选项
五 常见用法
1) 内存泄漏检测
在shell命令下执行 #setprop libc.debug.malloc.options "backtrace leak_track verbose"
这样开启后在进程退出时会打印leak信息,在发送kill -47时会打印当前内存申请
2) 内存崩溃检查
在shell命令中添加guard #setprop libc.debug.malloc.options "backtrace leak_track verbose guard"
这样会检测内存覆盖等检测
3) verify_pointers 开启可以检测use after free和double free等操作