آدرس ضد عفونی کننده

اندروید NDK از Address Sanitizer (که با نام ASan نیز شناخته می‌شود) با API سطح ۲۷ (اندروید O نسخه ۱) پشتیبانی می‌کند.

ASan ابزاری سریع مبتنی بر کامپایلر برای تشخیص اشکالات حافظه در کد بومی است. ASan موارد زیر را تشخیص می‌دهد:

  • سرریز/کم‌ریز بافر پشته و هیپ
  • استفاده از هیپ پس از آزادسازی
  • استفاده از پشته در خارج از محدوده
  • دو برابر رایگان/وحشی رایگان

سربار CPU در ASan تقریباً ۲ برابر، سربار اندازه کد بین ۵۰٪ تا ۲ برابر و سربار حافظه زیاد است (بسته به الگوهای تخصیص شما، اما از مرتبه ۲ برابر).

نمونه برنامه

A sample app shows how to configure a build variant for asan.

ساختن

برای ساخت کد بومی (JNI) برنامه خود با Address Sanitizer ، موارد زیر را انجام دهید:

ساخت ndk

در 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)، یک برنامه می‌تواند یک اسکریپت پوسته پوششی ارائه دهد که می‌تواند فرآیند برنامه را پوشش داده یا جایگزین کند. این به یک برنامه قابل اشکال‌زدایی اجازه می‌دهد تا راه‌اندازی برنامه خود را سفارشی کند، که امکان استفاده از ASan را در دستگاه‌های تولیدی فراهم می‌کند.

  1. Add android:debuggable to the application manifest.
  2. Set useLegacyPackaging to true in your app's build.gradle file. See the wrap shell script guide for more information.
  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
    "$@"
    

Assuming your project's application module is named app , your final directory structure should include the following:

<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

ردیابی پشته

Address Sanitizer needs to unwind the stack on every malloc / realloc / free call. There are two options here:

  1. یک بازکننده سریع مبتنی بر اشاره‌گر فریم. این چیزی است که با دنبال کردن دستورالعمل‌های بخش ساخت ، استفاده می‌شود.

  2. A "slow" CFI unwinder. In this mode ASan uses _Unwind_Backtrace . It requires only -funwind-tables , which is normally enabled by default.

باز کردن سریع، پیش‌فرض برای malloc/realloc/free است. باز کردن آهسته، پیش‌فرض برای ردیابی‌های پشته کشنده است. باز کردن آهسته را می‌توان برای همه ردیابی‌های پشته با اضافه کردن fast_unwind_on_malloc=0 به متغیر ASAN_OPTIONS در wrap.sh خود فعال کرد.