Adres Temizleyici'yi kullanarak Bellek Bozulması Hatalarını Ayıklama

Bu dokümanda, AGDE kullanılırken özel hata ayıklama araçlarının nasıl etkinleştirileceği gösterilmektedir. Bu araçlar, teşhisi zor olan bellek bozulması ve üzerine yazma hatalarında yardımcı olabilir.

HWAddress Sanitizer ve Address Sanitizer

HWAddress Sanitizer (HWASan) ve Address Sanitizer (ASan), bellek bozulması ve aşağıdaki gibi hataların üzerine yazma hatalarını ayıklamaya yardımcı olan bellek bozulması ayıklama araçlarıdır:

  • Yığın tamponu taşmaları ve eksik dolgular
  • Yığın tamponu taşmaları ve eksik dolgular
  • Stack'in kapsamı dışında kullanılması
  • İkili boşluk ve vahşi boşluk hataları
  • Döndürme işleminden sonra yığın kullanımı (yalnızca HWASan)

HWASan veya ASan'ı yalnızca bir sorunla ilgili hata ayıklama işlemi yaparken veya otomatik testin bir parçası olarak etkinleştirmenizi öneririz. Bu araçlar performans açısından iyi olsa da bunların kullanımı cezaya neden olur.

Çalışma zamanı davranışı

Etkinleştirildiğinde hem HWASan hem de ASan, uygulamanızdaki bellek bozulmasını otomatik olarak kontrol eder.

Bir bellek hatası algılanırsa uygulama SIGBART (sinyal iptal) hatasıyla kilitlenir ve logcat'e ayrıntılı bir mesaj yazdırır. İletinin bir kopyası da /data/tombstones altındaki bir dosyaya yazılır.

Hata mesajı aşağıdaki gibi görünür:

ERROR: HWAddressSanitizer: tag-mismatch on address 0x0042a0826510 at pc 0x007b24d90a0c
WRITE of size 1 at 0x0042a0826510 tags: 32/3d (ptr/mem) in thread T0
    #0 0x7b24d90a08  (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x2a08)
    #1 0x7b8f1e4ccc  (/apex/com.android.art/lib64/libart.so+0x198ccc)
    #2 0x7b8f1db364  (/apex/com.android.art/lib64/libart.so+0x18f364)
    #3 0x7b8f2ad8d4  (/apex/com.android.art/lib64/libart.so+0x2618d4)

0x0042a0826510 is located 0 bytes to the right of 16-byte region [0x0042a0826500,0x0042a0826510)
allocated here:
    #0 0x7b92a322bc  (/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so+0x212bc)
    #1 0x7b24d909e0  (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x29e0)
    #2 0x7b8f1e4ccc  (/apex/com.android.art/lib64/libart.so+0x198ccc)

Ön koşullar

HWASan gereksinimleri

HWASan'ı kullanmak için:

  • AGDE 24.1.99 veya daha yeni bir sürümü kullanmanız gerekir.
  • Uygulama, NDK 26 veya daha yeni bir sürüm kullanılarak derlenmiş olmalıdır.
  • Uygulama, hedef SDK 34 veya sonraki bir sürümle derlenmiş olmalıdır.
  • Hedef, Android 14 (API düzeyi 34) veya sonraki sürümleri çalıştıran bir arm64-v8a cihaz olmalıdır.

Projenizde paylaşılan C++ Standart Kitaplığı'nı kullanma

Bilinen bir sorun nedeniyle ASan, libc++_static kullanıldığında C++ istisna işlemeyle uyumlu değildir. Bu sorun, libc++_shared kullanılırken görülmez.

HWASan, new ve delete operatörlerinin kendi uygulamasını kullanır. Standart kitaplık projeye statik olarak bağlanırsa bu operatörler kullanılamaz.

Bu ayarı değiştirmek için bu dokümanın C++ Standart Kitaplığı'nı bağlama bölümüne bakın.

Çerçeve İşaretçisi oluşturmayı etkinleştir

HWASan ve ASan, bellek ayırma ve bellek ayırma etkinlikleri için yığın izleme bilgilerini oluşturmak üzere hızlı çerçeve işaretçisine dayalı bir çözücü kullanır. Bu, bu özellikleri kullanmak için C++ derleyici ayarlarınızda çerçeve işaretçisi oluşturmayı etkinleştirmeniz gerektiği anlamına gelir. Yani kare işaretçisi atlama optimizasyonunu devre dışı bırakmanız gerekir.

Bu ayarı değiştirmek için bu dokümanın Çerçeve İşaretçisi Oluşturma özelliğini etkinleştirme bölümüne bakın.

Visual Studio projenizi HWASan veya ASan kullanacak şekilde yapılandırma

HWASan veya ASan'ı etkinleştirme

HWASan veya ASan'ı etkinleştirmek için projenizin Mülk Sayfaları'nda Yapılandırma Özellikleri > Genel'e gidin.

Geçerli projenin Visual Studio Solution Explorer mülk menüsü.

Şekil 1: Visual Studio Çözüm Gezgini penceresindeki projenin Özellikler seçeneği.

Genel özelliklerin gösterildiği ve Adres Düzeltici ayarlarının vurgulandığı proje Tesis Sayfaları iletişim kutusu.

Şekil 2: Genel proje özelliklerindeki Address Sanitizer (ASan) ayarı.

Projeniz için HWASan'ı etkinleştirmek üzere Address Sanitizer (ASan) ayarını Hardware ASan Enabled (fsanitize=hwaddress) olarak değiştirin.

Projeniz için ASan'ı etkinleştirmek üzere Address Sanitizer (ASan) ayarını ASan Enabled (fsanitize=address) olarak değiştirin.

Çerçeve işaretçisi oluşturmayı etkinleştirme

Çerçeve İşaretçisi oluşturma, Çerçeve İşaretçisini Atla C/C++ derleyici ayarı tarafından kontrol edilir ve projenizdeki Yapılandırma Özellikleri > C/C++ > Optimizasyon altındaki Mülk Sayfaları'nda bulunabilir.

C/C++ Optimizasyon özelliklerinin gösterildiği ve Çerçeve İşaretçisini Atla ayarlarının vurgulandığı proje mülk sayfaları iletişim kutusu.

Şekil 3: Çerçeve İşaretçisini Atla ayarının bulunduğu yer.

HWASan veya ASan kullanırken Çerçeve İşaretçisini Atla ayarını Hayır (-fno-omit-frame-pointer) olarak ayarlayın.

C++ Standart Kitaplığı'nı paylaşılan kitaplık modunda bağlama

C++ Standart Kitaplığı için bağlayıcı modu ayarını, projenizin Özellik Sayfaları'ndaki Yapılandırma Özellikleri > Genel bölümündeki Proje Varsayanları bölümünde bulabilirsiniz.

Genel kategorisinin seçildiği ve STL Kullanımı ayarının vurgulandığı proje Mülk Sayfaları iletişim kutusu.

Şekil 4: C++ Standart Kitaplığı için bağlayıcı modu ayarının bulunduğu yer.

HWASan veya ASan kullanırken STL kullanımı'nı C++ Standart Kitaplıklarını (.so) kullan olarak ayarlayın. Bu değer, C++ standart kitaplığını paylaşılan kitaplık olarak projenize bağlar. Bu, HWASan ve ASan'ın düzgün çalışması için gereklidir.

Address Sanitizer kullanımı için derleme yapılandırması oluşturma

HWASan veya ASan'ı geçici olarak kullanmayı tercih ediyorsanız yalnızca bu ikisini kullanmak için yeni bir derleme yapılandırması oluşturmak istemeyebilirsiniz. Projeniz küçükse, özelliği keşfediyorsanız veya test sırasında keşfettiğiniz bir soruna yanıt olarak bu durumla karşılaşabilirsiniz.

Ancak bu özelliği faydalı bulup düzenli olarak kullanmayı planlıyorsanız Çaydanlık örneğinde gösterildiği gibi HWASan veya ASan için yeni bir derleme yapılandırması oluşturabilirsiniz. Örneğin, birim testlerinizin bir parçası olarak veya oyununuzun gece boyunca yapılan ilk testleri sırasında Address Sanitizer'ı düzenli olarak çalıştırırsanız bunu yapabilirsiniz.

Ayrı bir derleme yapılandırması oluşturmak, özellikle çok sayıda farklı üçüncü taraf kitaplığı kullanan ve bu kitaplıkları normalde C++ standart kitaplığına statik olarak bağladığınız büyük bir projeniz varsa yararlı olabilir. Özel derleme yapılandırmaları, proje ayarlarınızın her zaman doğru kalmasını sağlamanıza yardımcı olabilir.

Derleme yapılandırması oluşturmak için projenizin Mülk Sayfaları'nda Yapılandırma Yöneticisi… düğmesini tıklayın ve ardından Etkin çözüm yapılandırması açılır menüsünü açın. Ardından simgesini seçin ve uygun bir ada sahip yeni bir derleme yapılandırması oluşturun (örneğin, HWASan etkin).

HWASan'ı özel bellek ayırıcılarla kullanma

HWASan, işaretçilere etiket ekleyebilmesi ve etiket uyuşmazlıklarını kontrol edebilmesi için malloc (veya new) aracılığıyla ayrılan belleği otomatik olarak keser.

Ancak özel bellek ayırıcı kullanıldığında HWASan, özel bellek ayırma yöntemlerinize otomatik olarak müdahale edemez. Bu nedenle, HWASan'ı özel bellek ayırıcınızla kullanmak istiyorsanız bellek ayırıcınızı HWASan'ı açıkça çağıracak şekilde donatın. Bu işlem yalnızca birkaç satır kodla yapılabilir.

Ön koşullar

Çağırmanız gereken HWASan yöntemleri bu başlıkta tanımlanmıştır:

#include "sanitizer/hwasan_interface.h"

Bellek ayırma yönteminizin performansını ölçme

  1. Nesneleri 16 baytlık blok ayrıntı düzeyinde ve hizalamayla ayırın. Örneğin, 24 bayt boyutunda sabit boyutlu nesneler sunan bir havuz ayırıcınız varsa ayırma işlemlerinizi 32 bayta yuvarlayın ve 16 bayta hizalayın.

  2. 8 bitlik bir etiket oluşturun. Bu değerler dahili kullanım için ayrıldığından etiketinizde 0-16 değerleri kullanılmamalıdır.

  3. HWASan'ı etkinleştirerek bellek bölgesini bu etiketle izlemeye başlayın:

    __hwasan_tag_memory((void*) address, tag, size);
    
  4. Etiketi işaretçinizin üst 8 bitine ekleyin:

    address = __hwasan_tag_pointer((void*) address, tag);
    

Bellek ayırma yönteminizi ayarlama

  1. Mevcut etiketli işaretçiler aracılığıyla daha fazla erişimin başarısız olmasına neden olmak için bellek bölgesi etiketini sıfırlayın:

    __hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), 0, size);
    

Önceden ayrılmış bir nesne havuzuyla çalışma

Bellek ayırıcınız, nesneleri bir havuzda önceden ayırır ve gerçekten serbest bırakmak yerine havuza geri döndürüyorsa bellek ayırma yönteminiz, bellek ve işaretçi etiketinin doğrudan üzerine yeni bir değer yazabilir:

```
__hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), tag, size);
ptr = __hwasan_tag_pointer((void*)ptr, tag);
```

Bu tekniği kullanırsanız ayırma yöntemlerinizin işaretçileri veya bellek bloklarını etiketlemesi gerekmez. Bunun yerine, işaretçileri ve bellek bloklarını havuzunuzdaki nesneleri önceden ayırırken etiketlemeniz gerekir. Bu stilin kullanıldığı bir örnek için PoolAllocator örneğine bakın.