المعقّم للعنوان

يتوافق Android NDK مع Address Sanitizer (المعروف أيضًا باسم ASan) الذي يبدأ بالمستوى 27 من واجهة برمجة التطبيقات (Android O MR 1).

تُعد ASan أداة سريعة تستند إلى برنامج التحويل البرمجي لاكتشاف أخطاء الذاكرة في الرموز البرمجية الأصلية. يرصد نظام AAN ما يلي:

  • فائض/تدفق المخزن المؤقت للذاكرة الديناميكية (Heap-Buffer)
  • استخدام الذاكرة بعد انتهاء الفترة التجريبية المجانية
  • استخدام التكدس خارج النطاق
  • مزدوج مجاني/مجاني

تبلغ النفقات العامة لوحدة المعالجة المركزية في ASan ضعف تقريبًا، ويتراوح حجم الكود بين 50% و2x، وحجم الذاكرة الزائد كبير (يعتمد على أنماط التخصيص، ولكن على ترتيب 2x).

نموذج التطبيق

يعرض نموذج التطبيق كيفية تهيئة إصدار تجريبي لـ 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

CMaker

في ملف Build.grale في وحدتك:

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 (المستوى 27 من واجهة برمجة التطبيقات)، يمكن أن يوفّر التطبيق نص برمجي التفافي يمكنه التفاف عملية التطبيق أو استبدالها. يسمح ذلك للتطبيق القابل للتصحيح بتخصيص بدء تشغيل التطبيق، ما يتيح استخدام ASan على أجهزة الإنتاج.

  1. إضافة android:debuggable إلى بيان التطبيق
  2. اضبط السمة useLegacyPackaging على true في ملف build.gradle الخاص بتطبيقك. راجِع دليل نص التفاف النص للحصول على مزيد من المعلومات.
  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

تتبعات التكديس

يحتاج Address Sanitizer إلى الاسترخاء في الحزمة عند كل مكالمة malloc/realloc/free. وهناك خياران هنا:

  1. أداة "سريعة" للاسترخاء والمستندة إلى مؤشر الإطار ويتم استخدامه من خلال اتّباع التعليمات الواردة في قسم المبنى.

  2. جهاز فكّ ترميز CFI "البطيء". في هذا الوضع، يستخدم ASan _Unwind_Backtrace. تتطلّب هذه السياسة -funwind-tables فقط، والتي يتم تفعيلها عادةً بشكل تلقائي.

خيار "الفك السريع" هو الخيار التلقائي للمتسوّقينaloc/realloc/free. يُعد فك الضغط البطيء هو الإعداد الافتراضي لتتبعات تسلسل استدعاء الدوال البرمجية الفادحة. يمكن تفعيل أداة فك الضغط البطيء لجميع عمليات تتبُّع تسلسل استدعاء الدوال البرمجية من خلال إضافة fast_unwind_on_malloc=0 إلى المتغيّر ASAN_OPTIONS في ملف wrap.sh.