Android NDK รองรับการเริ่มต้นใช้งานตัวล้างที่อยู่ (หรือที่เรียกว่า ASan) ด้วย API ระดับ 27 (Android O MR 1)
ASan เป็นเครื่องมือที่ทำงานรวดเร็วที่ใช้คอมไพเลอร์เพื่อใช้ตรวจหาข้อบกพร่องของหน่วยความจําในโค้ดแบบเนทีฟ ASan ตรวจพบสิ่งต่อไปนี้
- สแต็กและฮีปบัฟเฟอร์ล้น/ล้นเกิน
- การใช้ฮีปหลังจากฟรี
- การใช้สแต็กนอกขอบเขต
- Double Free/Wild Free
โอเวอร์เฮดของ CPU ของ ASan จะอยู่ที่ราว 2 เท่า ส่วนโอเวอร์เฮดของขนาดโค้ดจะอยู่ที่ 50% ถึง 2 เท่า และค่าใช้จ่ายในหน่วยความจำก็มีขนาดใหญ่ (ขึ้นอยู่กับรูปแบบการจัดสรรของคุณ แต่ ลำดับของ 2x)
แอปตัวอย่าง
ตัวอย่างแอป แสดงวิธีกำหนดค่าเวอร์ชันบิลด์สำหรับ Asan
สร้าง
หากต้องการสร้างโค้ดเนทีฟ (JNI) ของแอปด้วย Address Sanitizer ให้ทำดังนี้ ดังต่อไปนี้:
Ndk-Build
ใน Application.mk ของคุณ
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
สำหรับแต่ละโมดูลใน Android.mk
LOCAL_ARM_MODE := arm
ผู้ผลิต
ใน Build.gradle ของโมดูล
android {
defaultConfig {
externalNativeBuild {
cmake {
// Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
สำหรับแต่ละเป้าหมายใน CMakeLists.txt
target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)
เรียกใช้
สำหรับ Android O MR1 (API ระดับ 27) แอปพลิเคชันสามารถให้ Wrapper ของสคริปต์ ที่สามารถรวมหรือแทนที่กระบวนการของแอปพลิเคชันได้ วิธีนี้ช่วยให้ แอปพลิเคชันที่แก้ไขข้อบกพร่องได้เพื่อปรับแต่งการเริ่มต้นแอปพลิเคชัน ซึ่งทำให้ โดยใช้ ASan บนอุปกรณ์ที่ใช้งานจริง
- เพิ่ม
android:debuggable
ลงในไฟล์ Manifest ของแอปพลิเคชัน - ตั้งค่า
useLegacyPackaging
ไปยังtrue
ในไฟล์build.gradle
ของแอป โปรดดูคำแนะนำเกี่ยวกับ Wrapper ของสคริปต์ในการรวม เพื่อดูข้อมูลเพิ่มเติม - เพิ่มไลบรารีรันไทม์ ASan ลงใน
jniLibs
ของโมดูลแอป เพิ่มไฟล์
wrap.sh
รายการที่มีเนื้อหาต่อไปนี้ลงในแต่ละไดเรกทอรีใน ไดเรกทอรีsrc/main/resources/lib
#!/system/bin/sh HERE="$(cd "$(dirname "$0")" && pwd)" export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1 ASAN_LIB=$(ls $HERE/libclang_rt.asan-*-android.so) if [ -f "$HERE/libc++_shared.so" ]; then # Workaround for https://github.com/android-ndk/ndk/issues/988. export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so" else export LD_PRELOAD="$ASAN_LIB" fi "$@"
สมมติว่าโมดูลแอปพลิเคชันของโปรเจ็กต์ชื่อ app
ไดเรกทอรีสุดท้ายของคุณ
ควรมีข้อมูลดังต่อไปนี้
<project root>
└── app
└── src
└── main
├── jniLibs
│ ├── arm64-v8a
│ │ └── libclang_rt.asan-aarch64-android.so
│ ├── armeabi-v7a
│ │ └── libclang_rt.asan-arm-android.so
│ ├── x86
│ │ └── libclang_rt.asan-i686-android.so
│ └── x86_64
│ └── libclang_rt.asan-x86_64-android.so
└── resources
└── lib
├── arm64-v8a
│ └── wrap.sh
├── armeabi-v7a
│ └── wrap.sh
├── x86
│ └── wrap.sh
└── x86_64
└── wrap.sh
สแต็กเทรซ
ตัวล้างที่อยู่ต้องคลายสแต็กทุก malloc
/realloc
/free
การโทร ซึ่งมี 2 ตัวเลือกดังต่อไปนี้
"เร็ว" โปรแกรมคลายการเลื่อนดูเฟรมภาพ นี่คือสิ่งที่ใช้โดยทำตาม วิธีการในส่วนอาคาร
"ช้า" โปรแกรมผ่อนคลาย CFI ในโหมดนี้ ASan ใช้
_Unwind_Backtrace
ทั้งนี้ ต้องการเพียง-funwind-tables
ซึ่งปกติจะเปิดใช้อยู่โดยค่าเริ่มต้น
โปรแกรมคลายเร็วเป็นค่าเริ่มต้นสําหรับ Malloc/realloc/free โปรแกรมคลายเครียดช้าๆ
ค่าเริ่มต้นสำหรับสแต็กเทรซที่ร้ายแรง โปรแกรมคลี่คลายที่ช้าสามารถเปิดใช้สำหรับ
สแต็กเทรซด้วยการเพิ่ม fast_unwind_on_malloc=0
ลงในตัวแปร ASAN_OPTIONS
ใน wrap.sh ของคุณ