相比于Asan和Valgrind繁琐的配置,HWAddress Sanitizer使用起来更加的简单,但前提是你有pixel3及以上型号的手机。
摘自官方文档
与传统的 ASan 相比,HWASan 具有如下特征:
- 类似的 CPU 开销(约为 2 倍)
- 类似的代码大小开销 (40 – 50%)
- 更小的 RAM 开销 (10% – 35%)
HWASan 能检测到 ASan 所能检测到的同一系列错误:
- 堆栈和堆缓冲区上溢/下溢
- 释放之后的堆使用情况
- 超出范围的堆栈使用情况
- 重复释放/错误释放
此外,HWASan 还可以检测:
- 返回之后的堆栈使用情况
示例:
#include <jni.h>
#include <string>
#include <stdlib.h>
#include <thread>
extern "C" JNIEXPORT void JNICALL
Java_com_example_sanitizertest_MainActivity_doUseAfterFree(
JNIEnv *env, jobject /* this */) {
char * volatile p = new char[10];
delete[] p;
p[5] = 42;
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_sanitizertest_MainActivity_doHeapBufferOverflow(
JNIEnv *env, jobject /* this */) {
char * volatile p = new char[16];
p[16] = 42;
delete[] p;
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_sanitizertest_MainActivity_doHeapBufferOverflowReadLoop(
JNIEnv *env, jobject /* this */) {
for (int i = 0; i < 0x10000; ++i) {
char * volatile p = new char[16];
volatile char x = p[32];
x++;
delete[] p;
}
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_sanitizertest_MainActivity_doDoubleFree(
JNIEnv *env, jobject /* this */) {
char * volatile p = new char[16];
delete[] p;
delete[] p;
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_sanitizertest_MainActivity_doNullDeref(
JNIEnv *env, jobject /* this */) {
char * volatile p = (char *)nullptr;
p[42] = 1;
}
static void RunUAFLoop() {
constexpr int kLoopCount = 100;
constexpr int kAllocCount = 1000;
volatile char sink;
char **p = new char*[kAllocCount];
for (int j = 0; j < kLoopCount; ++j) {
for (int i = 0; i < kAllocCount; ++i)
p[i] = new char[128];
for (int i = 0; i < kAllocCount; ++i)
delete[] p[i];
for (int i = 0; i < kAllocCount; ++i)
sink = p[i][42];
}
delete[] p;
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_sanitizertest_MainActivity_doUseAfterFreeLoop(
JNIEnv *env, jobject /* this */) {
std::thread t(RunUAFLoop);
t.detach();
}
1)接入教程
第一步:
根据你的pixel手机型号进行刷机,可以直接通过chrome刷机,比起命令行操作,简单不少,全部都是自动化操作;
第二步:
你可以在cmake中添加一个宏或者不加,通过flavor传递宏来控制是否进行内存检测,比如:
externalNativeBuild.cmake { arguments "-DHWASAN=1" }
第三步:
在cmakelist的target_link_libraries之后设置:
if (ANDROID_ABI STREQUAL "arm64-v8a" AND HWASAN)
target_compile_options(yourTarget PUBLIC -fsanitize=hwaddress -fno-omit-frame-pointer)
set_target_properties(yourTarget PROPERTIES LINK_FLAGS -fsanitize=hwaddress)
endif ()
yourTarget是你的库的名称,HWASan仅支持Android10(29 )以上和64位系统,并且要求NDK>=21;
第四步:
在刷好Rom的pixel手机上运行你的app即可,当检测到内存错误时,可以在 /data/tombstones
文件夹中找到对应的文件。