Adres Temizleyici

Android NDK, API düzeyi 27'den (Android O MR 1) itibaren Address Sanitizer'ı (ASan olarak da bilinir) destekler.

ASan, yerel kodda bellek hatalarını tespit etmek için kullanılan, derleyici tabanlı hızlı bir araçtır. ASan'ın algıladığı sorunlar:

  • Yığın ve bellek yığını arabellek taşması/taşma altı
  • Serbest bırakıldıktan sonra yığın kullanımı
  • Yığın kullanımı kapsam dışında
  • İki katı ücretsiz/wild ücretsiz

ASan'ın CPU ek yükü yaklaşık 2 kat, kod boyutu ek yükü% 50 ile 2 kat arasında ve bellek ek yükü büyüktür (ayırma kalıplarınıza bağlıdır ancak 2 kat civarındadır).

Sample App

Örnek bir uygulamada, asan için derleme değişkeninin nasıl yapılandırılacağı gösterilmektedir.

Derleme

Uygulamanızın yerel (JNI) kodunu Address Sanitizer ile oluşturmak için aşağıdakileri yapın:

ndk-build

Application.mk dosyanızda:

APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address

Android.mk dosyanızdaki her modül için:

LOCAL_ARM_MODE := arm

CMake

Modülünüzün build.gradle dosyasında:

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                // Can also use system or none as ANDROID_STL.
                arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
            }
        }
    }
}

CMakeLists.txt dosyanızdaki her hedef için:

target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)

Çalıştır

Android O MR1 (API düzeyi 27) sürümünden itibaren uygulamalar, uygulama sürecini sarmalayabilen veya değiştirebilen bir sarmalama kabuk komut dosyası sağlayabilir. Bu, hata ayıklanabilir bir uygulamanın uygulama başlangıcını özelleştirmesine olanak tanır. Bu sayede, üretim cihazlarında ASan kullanılabilir.

  1. Uygulama manifestine android:debuggable ekleyin.
  2. Uygulamanızın build.gradle dosyasında useLegacyPackaging değerini true olarak ayarlayın. Daha fazla bilgi için wrap kabuk komut dosyası kılavuzuna bakın.
  3. ASan çalışma zamanı kitaplığını uygulama modülünüzün jniLibs bölümüne ekleyin.
  4. wrap.sh dizininizdeki her dizine aşağıdaki içeriklere sahip wrap.sh dosyaları ekleyin.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
    "$@"
    

Projenizin uygulama modülünün app olarak adlandırıldığını varsayarsak nihai dizin yapınız şunları içermelidir:

<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

Yığın izleri

Address Sanitizer'ın her malloc/realloc/free çağrısında yığını geri sarması gerekir. Bu durumda iki seçeneğiniz vardır:

  1. "Hızlı" bir çerçeve işaretçisi tabanlı geri sarıcı. Bu, yapı bölümündeki talimatlar uygulandığında kullanılan öğedir.

  2. "Yavaş" bir CFI çözücü. Bu modda ASan, _Unwind_Backtrace kullanır. Bu özellik için yalnızca -funwind-tables gerekir. Bu özellik normalde varsayılan olarak etkindir.

Hızlı sarmalayıcı, malloc/realloc/free için varsayılandır. Yavaş çözücü, önemli yığın izlemeleri için varsayılandır. wrap.sh dosyanızdaki ASAN_OPTIONS değişkenine fast_unwind_on_malloc=0 ekleyerek yavaş sarmayı tüm yığın izleri için etkinleştirebilirsiniz.