अड्रेस सैनिटाइज़र

Android NDK, एपीआई लेवल 27 (Android O MR 1) से Address Sanitizer (इसे ASan भी कहा जाता है) के साथ काम करता है.

ASan, कंपाइलर पर आधारित एक टूल है. यह नेटिव कोड में मेमोरी से जुड़ी गड़बड़ियों का पता लगाता है. ASan इन समस्याओं का पता लगाता है:

  • स्टैक और हीप बफ़र ओवरफ़्लो/अंडरफ़्लो
  • फ़्री किए गए हीप का इस्तेमाल
  • स्कोप से बाहर स्टैक का इस्तेमाल किया गया
  • डबल फ़्री/वाइल्ड फ़्री

ASan का सीपीयू ओवरहेड करीब दो गुना होता है. कोड साइज़ का ओवरहेड 50% से दो गुना के बीच होता है. वहीं, मेमोरी का ओवरहेड ज़्यादा होता है. यह आपके ऐलोकेशन पैटर्न पर निर्भर करता है, लेकिन यह दो गुना के क्रम में होता है.

सैंपल ऐप्लिकेशन

सैंपल ऐप्लिकेशन में दिखाया गया है कि asan के लिए, बिल्ड वैरिएंट को कैसे कॉन्फ़िगर किया जाता है.

बनाएं

Address Sanitizer की मदद से, अपने ऐप्लिकेशन का नेटिव (JNI) कोड बनाने के लिए, यह तरीका अपनाएं:

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

CMake

अपने मॉड्यूल की 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 (एपीआई लेवल 27) से, कोई ऐप्लिकेशन रैप शेल स्क्रिप्ट उपलब्ध करा सकता है. यह स्क्रिप्ट, ऐप्लिकेशन प्रोसेस को रैप या बदल सकती है. इससे डीबग किए जा सकने वाले ऐप्लिकेशन को, ऐप्लिकेशन के स्टार्टअप को पसंद के मुताबिक बनाने की अनुमति मिलती है. इससे प्रोडक्शन डिवाइसों पर ASan का इस्तेमाल किया जा सकता है.

  1. ऐप्लिकेशन मेनिफ़ेस्ट में android:debuggable जोड़ें.
  2. अपने ऐप्लिकेशन की build.gradle फ़ाइल में, useLegacyPackaging को true पर सेट करें. ज़्यादा जानकारी के लिए, रैप शेल स्क्रिप्ट गाइड देखें.
  3. अपने ऐप्लिकेशन मॉड्यूल के jniLibs में ASan रनटाइम लाइब्रेरी जोड़ें.
  4. अपनी src/main/resources/lib डायरेक्ट्री में मौजूद हर डायरेक्ट्री में, यह कॉन्टेंट वाली wrap.sh फ़ाइलें जोड़ें.

    #!/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 की ज़रूरत होती है. यह आम तौर पर डिफ़ॉल्ट रूप से चालू होता है.

malloc/realloc/free के लिए, फ़ास्ट अनवाइंडर डिफ़ॉल्ट रूप से चालू होता है. स्लो अनवाइंडर, फ़ैटल स्टैक ट्रेस के लिए डिफ़ॉल्ट होता है. wrap.sh में ASAN_OPTIONS वैरिएबल में fast_unwind_on_malloc=0 जोड़कर, सभी स्टैक ट्रेस के लिए स्लो अनवाइंडर चालू किया जा सकता है.