AddressSanitizer (ASan), yerel koddaki bellek hatalarını algılamak için derleyici tabanlı hızlı bir araçtır.
ASan şunları algılar:
- 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 ücretsiz
ASan, hem 32-bit hem de 64-bit ARM'de, ayrıca x86 ve x86-64'te ç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ı, ancak 2x düzeyinde).
Android 10 ve AArch64'teki AOSP ana dalı, donanım hızlandırmalı ASan'ı (HWASan) destekler; buna benzer bir araç, daha düşük RAM yükü ve daha geniş bir algılanan hata yelpazesi sunar. HWASan, ASan tarafından tespit edilen hatalara ek olarak, dönüşten sonra yığın kullanımını algılar.
HWASan benzer CPU ve kod boyutu ek yüküne sahiptir, ancak çok daha küçük bir RAM ek yükü (%15). HWASan deterministik değildir. Yalnızca 256 olası etiket değeri vardır, bu nedenle herhangi bir hatayı kaçırmanın sabit %0,4 olasılığı vardır. HWASan, taşmaları algılamak için ASan'ın sınırlı boyutlu kırmızı bölgelerine ve boş kullanım sonrası 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 Android'de HWASan kullanımı hakkında daha fazla bilgi edinebilirsiniz.
ASan, yığın/genel yığın taşmalarının yanı sıra yığın taşmalarını da algılar ve minimum bellek yüküyle hızlıdır.
Bu belge, Android'in bölümlerinin/tümünün ASan ile nasıl oluşturulacağını ve çalıştırılacağını açıklar. Asan ile bir SDK/NDK uygulaması oluşturuyorsanız, bunun yerine Adres Temizleyici konusuna bakın.
ASan ile tek tek yürütülebilir dosyaları temizleme
Yürütülebilir dosya için derleme kuralına
LOCAL_SANITIZE:=address veya
sanitize: { address: true } ekleyin. Mevcut örnekler için kodu arayabilir veya diğer mevcut dezenfektanları bulabilirsiniz.
Bir hata tespit edildiğinde, ASan hem standart çıktıya hem de
logcat ayrıntılı bir rapor yazdırır ve ardından işlemi durdurur.
ASan ile paylaşılan kütüphaneleri dezenfekte etme
ASan'ın çalışma şekli nedeniyle, ASan ile oluşturulmuş bir kitaplık yalnızca ASan ile oluşturulmuş bir yürütülebilir dosya tarafından kullanılabilir.
Tamamı ASan ile oluşturulmamış 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ğıdakileri
Android.mk :
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 uygun bölümüne aşağıdakini ekleyin.
setenv LD_LIBRARY_PATH /system/lib/asan
/system/lib/asan mevcut olduğunda
/proc/$PID/maps okuyarak işlemin /system/lib/asan dizinindeki 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 ayırma ve ayırma olayı için bir yığın izlemesi kaydetmek için 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ı kare elde edersiniz. Bunu düzeltmek için kitaplığı ASan ile yeniden oluşturun (önerilir!) veya şununla:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
Veya işlem ortamında
ASAN_OPTIONS=fast_unwind_on_malloc=0 olarak ayarlayın. İkincisi, yüke bağlı olarak çok CPU yoğun olabilir.
sembolizasyon
Başlangıçta, ASan raporları ikili dosyalardaki ve paylaşılan kitaplıklardaki ofsetlere referanslar içerir. Kaynak dosya ve satır bilgilerini almanın iki yolu vardır:
-
llvm-symbolizerikili dosyasının
/system/biniçinde bulunduğundan emin olun.
llvm-symbolizer,
third_party/llvm/tools/llvm-symbolizeriçindeki kaynaklardan oluşturulmuştur.
- Raporu
external/compiler-rt/lib/asan/scripts/symbolize.pykomut dosyası aracılığıyla filtreleyin.
İkinci yaklaşım, ana bilgisayarda sembolize edilmiş kitaplıkların mevcudiyeti nedeniyle daha fazla veri (yani
file:line konumları) sağlayabilir.
Asan uygulamalarda
ASan Java kodunu göremez, ancak JNI kitaplıklarındaki hataları algılayabilir. Bunun için, yürütülebilir dosyayı bu durumda
/system/bin/app_process( 32|64 ) olan ASan ile oluşturmanız gerekir. Bu, cihazdaki tüm uygulamalarda aynı anda Asan'ı etkinleştirir, bu da ağır bir yüktür, ancak 2 GB RAM'e sahip bir cihaz bunu kaldırabilmelidir.
LOCAL_SANITIZE:=address ,
frameworks/base/cmds/app_process içindeki
app_process derleme kuralına ekleyin. Şimdilik aynı dosyadaki
app_process__asan hedefini yoksayı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ü, aynı miktarda girintili
class main içeren girintili satırlar bloğuna aşağıdaki satırları eklemek için düzenleyin:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
Derleme, adb senkronizasyonu, hızlı önyükleme flash önyüklemesi ve yeniden başlatma.
sarma özelliğini kullanma
Önceki bölümdeki yaklaşım, sistemdeki her uygulamaya (aslında, Zygote sürecinin her soyundan gelene) ASan yerleştirir. ASan ile yalnızca bir (veya birkaç) uygulamayı çalıştırmak, daha yavaş uygulama başlatma için bir miktar bellek yükü ticareti yapmak mümkündür.
Bu, uygulamanızı
wrap. Emlak. 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şturulan
/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
asanwrapper
/system/lib 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 bir kerede oluşturma desteği içerir. (Android 9'dan daha yüksek bir sürüm oluşturuyorsanız, HWASan daha iyi bir seçimdir.)
Aynı yapı ağacında aşağıdaki komutları çalıştırın.
make -j42
SANITIZE_TARGET=address make -j42
Bu modda,
userdata.img fazladan kitaplıklar içerir ve cihaza da flash edilmesi gerekir. Aşağıdaki komut satırını kullanın:
fastboot flash userdata && fastboot flashall
Bu, iki paylaşılan kitaplık kümesi oluşturur:
/system/lib lib'de normal (ilk başlatma başlatma) ve
/data/asan/lib lib'de ASan enstrümanlı (ikinci başlatma başlatma). İkinci derlemedeki yürütülebilir dosyalar, ilk derlemedekilerin üzerine yazar. ASan araçlı yürütülebilir dosyalar, PT_INTERP içinde
/system/bin/linker_asan kullanımı yoluyla /system/lib'den önce
/system/lib
/data/asan/lib içeren farklı bir kitaplık arama yolu
PT_INTERP .
$SANITIZE_TARGET değeri değiştiğinde yapı sistemi ara nesne dizinlerini engeller. Bu,
/system/lib altındaki kurulu ikili dosyaları 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:=falsehedefler
-
LOCAL_SANITIZE:=false,
SANITIZE_TARGET=addressiçin ASan'd değil
Bunun gibi yürütülebilir dosyalar
SANITIZE_TARGET yapısında atlanır ve ilk make çağrısından gelen sürüm
/system/bin içinde bırakılır.
Bunun gibi kütüphaneler ASan olmadan inşa edilir. Bağlı oldukları statik kitaplıklardan bazı ASan kodları içerebilirler.