一 簡述
前面介紹了malloc_debug功能盾计,用來進(jìn)行內(nèi)存泄露等檢測(cè)变勇,其實(shí)android可以使用多種方法進(jìn)行內(nèi)存相關(guān)的監(jiān)控霍衫。比如利用llvm功能再編譯時(shí)添加內(nèi)存的相關(guān)檢測(cè)嫡秕。Android R默認(rèn)開啟了scudo新蟆。
scudo這個(gè)選項(xiàng)主要功能是再分配內(nèi)存時(shí)會(huì)添加64 bit的Header
// Our header requires 64 bits of storage. Having the offset saves us from
// using functions such as GetBlockBegin, that is fairly costly. Our first
// implementation used the MetaData as well, which offers the advantage of
// being stored away from the chunk itself, but accessing it was costly as
// well. The header will be atomically loaded and stored.
typedef u64 PackedHeader;
struct UnpackedHeader {
u64 Checksum : 16;
u64 ClassId : 8;
u64 SizeOrUnusedBytes : 20; // Size for Primary backed allocations, amount of
// unused bytes in the chunk for Secondary ones.
u64 State : 2; // available, allocated, or quarantined
u64 AllocType : 2; // malloc, new, new[], or memalign
u64 Offset : 16; // Offset from the beginning of the backend
// allocation to the beginning of the chunk
// itself, in multiples of MinAlignment. See
// comment about its maximum value and in init().
};
開啟scudo后支持的報(bào)錯(cuò)類型有如下谚赎,主要是用來進(jìn)行邊界檢查诬烹,檢測(cè)內(nèi)存越界
void NORETURN reportCallocOverflow(uptr Count, uptr Size);
void NORETURN reportPvallocOverflow(uptr Size);
void NORETURN reportAllocationAlignmentTooBig(uptr Alignment,
uptr MaxAlignment);
void NORETURN reportAllocationAlignmentNotPowerOfTwo(uptr Alignment);
void NORETURN reportInvalidPosixMemalignAlignment(uptr Alignment);
void NORETURN reportInvalidAlignedAllocAlignment(uptr Size, uptr Alignment);
void NORETURN reportAllocationSizeTooBig(uptr UserSize, uptr TotalSize,
uptr MaxSize);
void NORETURN reportRssLimitExceeded();
void NORETURN reportOutOfMemory(uptr RequestedSize);
二 android R開啟scudo功能
Android R使用的不是llvm的scudo功能此虑,因此不是通過soong的scudo的開啟來開啟憎妙,主要使用如下選項(xiàng)
MALLOC_SVELTE := true
go版本默認(rèn)是關(guān)閉scudo功能的库正。
非go版本四都開啟scudo功能的,不過不是通過llvm開啟厘唾,開啟的方法
libc_scudo_product_variables
在 libc_scudo_product_variables 中定義了 -DUSE_SCUDO褥符,具體的內(nèi)存分配會(huì)使用libscudo下的定義,libscudo代碼在externl/scudo下抚垃,而不是llvm中喷楣。
通過搜索USE_SCUDO宏,在宏開啟后
libc/bionic/malloc_common.h
#if defined(USE_SCUDO)
#include "scudo.h"
#define Malloc(function)scudo_ ## function
通過hook的方式鹤树,將Libscudo中的實(shí)現(xiàn)來替換Libc原有的內(nèi)存分配釋放實(shí)現(xiàn)铣焊。
三 llvm中的scudo實(shí)現(xiàn)方式
llvm的scudo主要是在代碼路徑compiler-rt\lib\scudo中,scudo只能與undefined一塊使用
The only other Sanitizer Scudo is compatible with is UBSan (eg: -fsanitize=scudo,undefined)
llvm下主要的生效方式是:
// You'll need to:
// 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in
// your source file. See the notes below for cases when
// INTERCEPTOR_WITH_SUFFIX(...) should be used instead.
// 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo".
// INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was
// intercepted successfully.
在庫初始化中罕伯,INTERCEPT_FUNCTION調(diào)用替代原生的函數(shù)曲伊,從而實(shí)現(xiàn)類似hook的方式。