ตัวฆ่าเชื้อที่อยู่

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 บนอุปกรณ์ที่ใช้งานจริง

  1. เพิ่ม android:debuggable ลงในไฟล์ Manifest ของแอปพลิเคชัน
  2. ตั้งค่า useLegacyPackaging ไปยัง true ในไฟล์ build.gradle ของแอป โปรดดูคำแนะนำเกี่ยวกับ Wrapper ของสคริปต์ในการรวม เพื่อดูข้อมูลเพิ่มเติม
  3. เพิ่มไลบรารีรันไทม์ ASan ลงใน jniLibs ของโมดูลแอป
  4. เพิ่มไฟล์ 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 ตัวเลือกดังต่อไปนี้

  1. "เร็ว" โปรแกรมคลายการเลื่อนดูเฟรมภาพ นี่คือสิ่งที่ใช้โดยทำตาม วิธีการในส่วนอาคาร

  2. "ช้า" โปรแกรมผ่อนคลาย CFI ในโหมดนี้ ASan ใช้ _Unwind_Backtrace ทั้งนี้ ต้องการเพียง -funwind-tables ซึ่งปกติจะเปิดใช้อยู่โดยค่าเริ่มต้น

โปรแกรมคลายเร็วเป็นค่าเริ่มต้นสําหรับ Malloc/realloc/free โปรแกรมคลายเครียดช้าๆ ค่าเริ่มต้นสำหรับสแต็กเทรซที่ร้ายแรง โปรแกรมคลี่คลายที่ช้าสามารถเปิดใช้สำหรับ สแต็กเทรซด้วยการเพิ่ม fast_unwind_on_malloc=0 ลงในตัวแปร ASAN_OPTIONS ใน wrap.sh ของคุณ