AddressSanitizer (ASan), yerel koddaki bellek hatalarını tespit etmek için derleyici tabanlı hızlı bir araçtır.
ASan şunları tespit eder:
- Yığın ve yığın arabellek taşması/yetersizliği
- Serbest kaldıktan sonra yığın kullanımı
- Kapsam dışında yığın kullanımı
- Çift serbest/vahşi serbest
ASan, hem 32 bit hem de 64 bit ARM ile x86 ve x86-64 üzerinde çalışır. ASan'ın CPU ek yükü kabaca 2x, kod boyutu ek yükü %50 ile 2x arasında ve büyük bir bellek ek yükü (tahsis modellerinize bağlıdır, ancak 2x mertebesinde).
AArch64'teki Android 10 ve AOSP ana dalı, daha düşük RAM ek yükü ve daha geniş bir algılanan hata yelpazesine sahip benzer bir araç olan donanım hızlandırmalı ASan'ı (HWASan) destekler. HWASan, ASan tarafından tespit edilen hatalara ek olarak dönüşten sonra yığın kullanımını tespit eder.
HWASan, benzer CPU ve kod boyutu ek yüküne sahiptir, ancak çok daha küçük bir RAM ek yüküne (%15) sahiptir. HWASan deterministik değildir. Yalnızca 256 olası etiket değeri vardır, dolayısıyla herhangi bir hatayı kaçırma olasılığı %0,4'tür. HWASan, taşmaları algılamak için ASan'ın sınırlı boyutlu kırmızı bölgelerine ve serbest kullanımdan sonra kullanımı algılamak için sınırlı kapasiteli karantinaya sahip değildir, bu nedenle HWASan için taşmanın ne kadar büyük olduğu veya belleğin ne kadar süre önce serbest bırakıldığı önemli değildir. Bu, HWASan'ı ASan'dan daha iyi yapar. HWASan'ın tasarımı veya HWASan'ın Android'de kullanımı hakkında daha fazla bilgi edinebilirsiniz.
ASan, yığın taşmalarına ek olarak yığın/genel taşmaları da algılar ve minimum bellek yüküyle hızlıdır.
Bu belge, Android'in bazı kısımlarını/tümünü ASan ile nasıl oluşturacağınızı ve çalıştıracağınızı açıklar. ASan ile bir SDK/NDK uygulaması oluşturuyorsanız bunun yerine Adres Temizleyici'ye bakın.
ASan ile bağımsız yürütülebilir dosyaları sterilize etme
Yürütülebilir dosya için oluşturma kuralına LOCAL_SANITIZE:=address
veya sanitize: { address: true }
ekleyin. Mevcut örnekler için kodda arama yapabilir veya mevcut diğer dezenfektanları bulabilirsiniz.
Bir hata algılandığında, ASan hem standart çıktıya hem de logcat
ayrıntılı bir rapor yazdırır ve ardından işlemi çökertir.
ASan ile paylaşılan kitaplıkları temizleme
ASan'ın çalışma şekli nedeniyle, ASan ile oluşturulan bir kitaplık yalnızca ASan ile oluşturulmuş bir yürütülebilir dosya tarafından kullanılabilir.
Tamamı ASan ile oluşturulmayan birden çok yürütülebilir dosyada kullanılan paylaşılan bir kitaplığı sterilize etmek için kitaplığın iki kopyasına ihtiyacınız vardır. Bunu yapmanın önerilen yolu, söz konusu modül için aşağıdakini Android.mk
eklemektir:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
Bu, kitaplığı /system/lib/asan
yerine /system/lib
içine yerleştirir. Ardından yürütülebilir dosyanızı şununla çalıştırın:
LD_LIBRARY_PATH=/system/lib/asan
Sistem arka plan programları için /init.rc
veya /init.$device$.rc
öğelerinin uygun bölümüne aşağıdakileri ekleyin.
setenv LD_LIBRARY_PATH /system/lib/asan
/proc/$PID/maps
okuyarak, işlemin mevcut olduğunda /system/lib/asan
kitaplıkları kullandığını doğrulayın. Değilse, SELinux'u devre dışı bırakmanız gerekebilir:
adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID # if it is a system service, or may be adb shell stop; adb shell start.
Daha iyi yığın izleri
ASan, programdaki her bellek tahsisi ve serbest bırakma olayı için bir yığın izlemesi kaydetmek üzere hızlı, çerçeve işaretçisi tabanlı bir çözücü kullanır. Android'in çoğu çerçeve işaretçileri olmadan oluşturulmuştur. Sonuç olarak, genellikle yalnızca bir veya iki anlamlı çerçeve elde edersiniz. Bunu düzeltmek için kitaplığı ASan (önerilen!) ile veya şunu kullanarak yeniden oluşturun:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
Veya işlem ortamında ASAN_OPTIONS=fast_unwind_on_malloc=0
ayarlayın. İkincisi, yüke bağlı olarak çok CPU yoğun olabilir.
simgeleştirme
Başlangıçta ASan raporları, ikili dosyalar ve paylaşılan kitaplıklardaki ofsetlere referanslar içerir. Kaynak dosya ve satır bilgilerini almanın iki yolu vardır:
-
llvm-symbolizer
ikili dosyasının/system/bin
içinde bulunduğundan emin olun.llvm-symbolizer
third_party/llvm/tools/llvm-symbolizer
içindeki kaynaklardan oluşturulmuştur. - Raporu
external/compiler-rt/lib/asan/scripts/symbolize.py
betiği aracılığıyla filtreleyin.
İkinci yaklaşım, ana bilgisayarda simgeleştirilmiş kitaplıkların mevcudiyeti nedeniyle daha fazla veri (yani file:line
konumları) sağlayabilir.
Uygulamalarda ASan
ASan, Java kodunu göremez, ancak JNI kitaplıklarındaki hataları algılayabilir. Bunun için, bu durumda /system/bin/app_process( 32|64 )
olan ASan ile yürütülebilir dosyayı oluşturmanız gerekir. Bu, ASan'ı cihazdaki tüm uygulamalarda aynı anda etkinleştirir ki bu ağır bir yüktür, ancak 2 GB RAM'e sahip bir cihaz bunu kaldırabilmelidir.
frameworks/base/cmds/app_process
içindeki app_process
derleme kuralına LOCAL_SANITIZE:=address
ekleyin. Şimdilik aynı dosyadaki app_process__asan
hedefini yok sayın (bunu okuduğunuz sırada hala oradaysa).
Uygun system/core/rootdir/init.zygote( 32|64 ).rc
dosyasının service zygote
bölümünü düzenleyerek class main
içeren ve yine aynı miktarda girintili olan girintili satırlar bloğuna aşağıdaki satırları ekleyin:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
Derleyin, adb senkronizasyonu yapın, hızlı önyükleme yapın ve yeniden başlatın.
sarma özelliğini kullanma
Önceki bölümdeki yaklaşım, ASan'ı sistemdeki her uygulamaya (aslında Zygote sürecinin her soyuna) yerleştirir. ASan ile yalnızca bir (veya birkaç) uygulama çalıştırmak, daha yavaş uygulama başlatma için bir miktar bellek yükü takas etmek mümkündür.
Bu, uygulamanızı wrap.
mülk. Aşağıdaki örnek, Gmail uygulamasını ASan altında çalıştırır:
adb root
adb shell setenforce 0 # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"
Bu bağlamda asanwrapper
/system/bin/app_process
ASan ile oluşturulmuş /system/bin/asan/app_process
olarak yeniden yazar. Ayrıca, dinamik kitaplık arama yolunun başına /system/lib/asan
ekler. Bu şekilde, asanwrapper
ile çalışırken /system/lib/asan
ASan enstrümanlı kitaplıklar /system/lib
normal kitaplıklara tercih edilir.
Bir hata bulunursa uygulama çöker ve rapor günlüğe yazdırılır.
SANITIZE_TARGET
Android 7.0 ve üstü, tüm Android platformunu ASan ile aynı anda oluşturmak için destek içerir. (Android 9'dan daha yüksek bir sürüm oluşturuyorsanız, HWASan daha iyi bir seçimdir.)
Aşağıdaki komutları aynı yapı ağacında çalıştırın.
make -j42
SANITIZE_TARGET=address make -j42
Bu modda, userdata.img
fazladan kitaplıklar içerir ve cihaza da flash ile yüklenmelidir. Aşağıdaki komut satırını kullanın:
fastboot flash userdata && fastboot flashall
Bu, iki dizi paylaşılan kitaplık oluşturur: /system/lib
içinde normal (ilk make çağrısı) ve /data/asan/lib
içinde ASan-cihazlı (ikinci make çağrısı). İkinci yapıdaki yürütülebilir dosyalar, ilk yapıdakilerin üzerine yazılır. ASan-enstrümanlı yürütülebilir dosyalar, PT_INTERP
/ /system/bin/linker_asan
/system/lib
önce /data/asan/lib
içeren farklı bir kitaplık arama yolu elde eder.
Yapı sistemi, $SANITIZE_TARGET
değeri değiştiğinde ara nesne dizinlerini tıkar. Bu, kurulu ikili dosyaları /system/lib
altında korurken tüm hedeflerin yeniden oluşturulmasını zorlar.
Bazı hedefler ASan ile oluşturulamaz:
- Statik olarak bağlantılı yürütülebilir dosyalar
-
LOCAL_CLANG:=false
hedefler -
LOCAL_SANITIZE:=false
SANITIZE_TARGET=address
için ASan'lı değil
Bunun gibi yürütülebilir dosyalar SANITIZE_TARGET
derlemesinde atlanır ve ilk make çağrısının sürümü /system/bin
içinde bırakılır.
Bunun gibi kütüphaneler ASan olmadan inşa edilmiştir. Bağımlı oldukları statik kitaplıklardan bazı ASan kodları içerebilirler.