Omówienie raportów HWASan

Gdy narzędzie HWASan wykryje błąd pamięci, proces zostanie zakończony za pomocą funkcji abort(), a raport zostanie wydrukowany w stderr i logcat. Podobnie jak wszystkie awarie natywne w Androidzie, błędy HWASan znajdują się w katalogu /data/tombstones.

Przykładowy raport

W porównaniu ze zwykłymi awariami natywnymi HWASan zawiera dodatkowe informacje w polu Abort message (Komunikat o przerwaniu) u góry zrzutu. Oto przykładowa awaria oparta na stercie. W przypadku błędów stosu zapoznaj się z uwagą w sekcjach dotyczących stosu.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/flame_hwasan/flame:Tiramisu/MASTER/7956676:userdebug/dev-keys'
Revision: 'DVT1.0'
ABI: 'arm64'
Timestamp: 2019-04-24 01:13:22+0000
pid: 11154, tid: 11154, name: sensors@1.0-ser  >>> /vendor/bin/hw/android.hardware.sensors@1.0-service <<<
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: '

[...]

[0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5








[ … regular crash dump follows …]

Jest to podobne do raportu AddressSanitizer. W przeciwieństwie do niego prawie wszystkie błędy HWASan to błędy niezgodności tagów, czyli dostęp do pamięci, w którym tag wskaźnika nie pasuje do odpowiedniego tagu pamięci. Może to być dowolny z tych błędów:

  • Dostęp poza zakresem na stosie lub stercie
  • Błąd użycia po zwolnieniu na stercie
  • Błąd użycia po powrocie na stosie

Sekcje

Poniżej znajdziesz wyjaśnienie każdej sekcji raportu HWASan.

Błąd dostępu

Zawiera informacje o nieprawidłowym dostępie do pamięci, w tym:

  • Typ dostępu (READ lub WRITE)
  • Rozmiar dostępu (liczba bajtów, do których próbowano uzyskać dostęp)
  • Numer wątku dostępu
  • Tagi wskaźnika i pamięci (do zaawansowanego debugowania)

Zrzut stosu dostępu

Zrzut stosu nieprawidłowego dostępu do pamięci. Aby go zsymbolizować, zapoznaj się z sekcją Symbolizacja to symbolize.

Przyczyna

Potencjalna przyczyna nieprawidłowego dostępu. Jeśli jest kilka możliwych przyczyn, są one wymienione w kolejności malejącego prawdopodobieństwa. Poprzedza szczegółowe informacje o potencjalnej przyczynie. HWASan może zdiagnozować te przyczyny:

  • Użycie po zwolnieniu
  • Niezgodność tagów stosu, która może być spowodowana użyciem stosu po powrocie, użyciem stosu po zakresie lub wyjściem poza zakres
  • Przepełnienie bufora sterty
  • Przepełnienie globalne

Informacje o pamięci

Opisuje, co HWASan wie o pamięci, do której uzyskuje się dostęp. Może się różnić w zależności od typu błędu:

Typ błędu Przyczyna Format raportu
Niezgodność tagów Użycie po zwolnieniu Użyj tego formatu raportu:
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
Przepełnienie bufora sterty Pamiętaj, że może to być też niedomiar.
<address> is located N bytes to the right of M-byte region [<start>, <end>)
allocated here:
Niezgodność tagów stosu Raporty stosu nie rozróżniają przepełnienia, niedomiaru i błędów użycia po powrocie. Ponadto, aby znaleźć alokację stosu, która jest źródłem błędu, wymagany jest krok symbolizacji offline. Zapoznaj się z sekcją Omówienie raportów stosu.
Nieprawidłowe zwolnienie Użycie po zwolnieniu Błąd podwójnego zwolnienia. Jeśli wystąpi to podczas zamykania procesu, może to oznaczać naruszenie ODR.
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
Nie można opisać adresu Albo zwolnienie niekontrolowane (zwolnienie pamięci, która nie została wcześniej przydzielona), albo podwójne zwolnienie po usunięciu przydzielonej pamięci z bufora wolnego HWASan.
0x... to pamięć cienia HWASan Zwolnienie niekontrolowane, ponieważ aplikacja próbowała zwolnić pamięć wewnętrzną HWASan.

Zrzut stosu dealokacji

Zrzut stosu miejsca, w którym pamięć została zwolniona. Występuje tylko w przypadku błędów użycia po zwolnieniu lub nieprawidłowego zwolnienia. Aby go zsymbolizować, zapoznaj się z sekcją Symbolizacja.

Zrzut stosu alokacji

Zrzut stosu miejsca, w którym pamięć została przydzielona. Aby go zsymbolizować, zapoznaj się z sekcją Symbolizacja.

Zaawansowane informacje na potrzeby debugowania

Raport HWASan zawiera też zaawansowane informacje na potrzeby debugowania, w tym (w kolejności):

  1. Lista wątków w procesie
  2. Lista wątków w procesie
  3. Wartość tagów pamięci w pobliżu pamięci powodującej błąd
  4. Zrzut rejestrów w momencie dostępu do pamięci

Zrzut tagów pamięci

Możesz użyć zrzutu tagów pamięci, aby wyszukać pobliskie alokacje pamięci z tym samym tagiem co tag wskaźnika. Tagi te mogą wskazywać na dostęp poza zakresem z dużym przesunięciem. Jeden tag odpowiada 16 bajtom pamięci. Tag wskaźnika to 8 najwyższych bitów adresu. Zrzut tagów pamięci może zawierać wskazówki, np. poniżej znajduje się przepełnienie bufora po prawej stronie:

tags: ad/5c (ptr/mem)
[...]
Memory tags around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: 0e  0e  0e  57  20  20  20  20  20  2e  5e  5e  5e  5e  5e  b5
=>0x006f33ae2000: f6  f6  f6  f6  f6  4c  ad  ad  ad  ad  ad  ad [5c] 5c  5c  5c
  0x006f33ae2010: 5c  04  2e  2e  2e  2e  2e  2f  66  66  66  66  66  80  6a  6a
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: ab  52  eb  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
=>0x006f33ae2000: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. [..] ..  ..  ..
  0x006f33ae2010: ..  5c  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..

Zwróć uwagę na ciąg 6 × 16 = 96 bajtów tagów ad po lewej stronie, które pasują do tagu wskaźnika.

Jeśli rozmiar alokacji nie jest wielokrotnością liczby 16, reszta rozmiaru jest przechowywana jako tag pamięci, a tag jest przechowywany jako krótki tag granulki. W poprzednim przykładzie tuż po alokacji oznaczonej tagiem ad mamy alokację o rozmiarze 5 × 16 + 4 = 84 bajty z tagiem 5c.

Tag pamięci o wartości zero (np. tags: ad/00 (ptr/mem)) wskazuje na błąd użycia stosu po powrocie.

Zrzut rejestrów

Zrzut rejestrów w raportach HWASan odpowiada instrukcji, która wykonała nieprawidłowy dostęp do pamięci. Po tym zrzucie następuje kolejny zrzut rejestrów z regularnego modułu obsługi sygnałów Androida. Zignoruj drugi zrzut, ponieważ został on wykonany, gdy HWASan wywołał funkcję abort() i nie jest związany z błędem.

Symbolizacja

Aby uzyskać nazwy funkcji i numery wierszy w zrzutach stosu (oraz nazwy zmiennych w przypadku błędów użycia po zakresie), wymagany jest krok symbolizacji offline.

Pierwsza konfiguracja: zainstaluj llvm-symbolizer

Aby zsymbolizować, w systemie musi być zainstalowany program llvm-symbolizer, który musi być dostępny z $PATH. W Debianie możesz go zainstalować za pomocą polecenia sudo apt install llvm.

Pobieranie plików symboli

Do symbolizacji wymagamy niepozbawionych symboli plików binarnych. Ich lokalizacja zależy od typu kompilacji:

  • W przypadku kompilacji lokalnych pliki symboli znajdują się w out/target/product/<product>/symbols/.
  • W przypadku kompilacji AOSP (np. flashowanych za pomocą narzędzia Android Flash Tool) kompilacje znajdują się w Android CI. W sekcji Artifacts (Artefakty) kompilacji znajduje się plik ${PRODUCT}-symbols-${BUILDID}.zip.
  • W przypadku kompilacji wewnętrznych z Twojej organizacji informacje o tym, jak uzyskać pliki symboli, znajdziesz w dokumentacji organizacji.

Symbolizacja

hwasan_symbolize --symbols <DECOMPRESSED_DIR>/out/target/product/*/symbols < crash

Omówienie raportów stosu

W przypadku błędów występujących w zmiennych stosu raport HWASan zawiera takie szczegóły:

Cause: stack tag-mismatch
Address 0x007d4d251e80 is located in stack of thread T64
Thread: T64 0x0074000b2000 stack: [0x007d4d14c000,0x007d4d255cb0) sz: 1088688 tls: [0x007d4d255fc0,0x007d4d259000)
Previously allocated frames:
  record_addr:0x7df7300c98 record:0x51ef007df3f70fb0  (/apex/com.android.art/lib64/libart.so+0x570fb0)
  record_addr:0x7df7300c90 record:0x5200007df3cdab74  (/apex/com.android.art/lib64/libart.so+0x2dab74)
  [...]

Aby pomóc Ci zrozumieć błędy stosu, HWASan śledzi poprzednie ramki stosu. HWASan nie przekształca ich w raportach o błędach w treści zrozumiałe dla człowieka i wymaga dodatkowego kroku symbolizacji.

Naruszenia ODR

Niektóre błędy użycia po zwolnieniu zgłaszane przez HWASan mogą wskazywać na naruszenie reguły jednej definicji (ODR). Naruszenie ODR występuje, gdy ta sama zmienna jest zdefiniowana kilka razy w tym samym programie. Oznacza to również, że zmienna jest niszczona kilka razy, co może prowadzić do błędu użycia po zwolnieniu.

Po symbolizacji naruszenia ODR powodują wyświetlenie błędu użycia po zwolnieniu z funkcją __cxa_finalize zarówno w stosie nieprawidłowego dostępu, jak i w stosie freed here (zwolniono tutaj). Stos previously allocated here (wcześniej przydzielono tutaj) zawiera funkcję __dl__ZN6soinfo17call_constructorsEv i powinien wskazywać lokalizację w programie, która definiuje zmienną wyżej w stosie.

Reguła ODR może zostać naruszona, jeśli używane są biblioteki statyczne. Jeśli biblioteka statyczna, która definiuje globalną zmienną C++, jest połączona z kilkoma bibliotekami współdzielonymi lub plikami wykonywalnymi, w tej samej przestrzeni adresowej może istnieć kilka definicji tego samego symbolu, co powoduje błąd ODR.

Rozwiązywanie problemów

W tej sekcji opisujemy niektóre błędy i sposoby ich rozwiązywania.

HWAddressSanitizer nie może dokładniej opisać adresu

Czasami HWASan może zabraknąć miejsca na informacje o poprzednich alokacjach pamięci. W takim przypadku raport zawiera tylko 1 zrzut stosu bezpośredniego dostępu do pamięci, a następnie notatkę:

HWAddressSanitizer can not describe address in more detail.

W niektórych przypadkach możesz rozwiązać ten problem, kilkakrotnie uruchamiając test. Możesz też zwiększyć rozmiar historii HWASan. Możesz to zrobić globalnie w pliku build/soong/cc/sanitize.go (wyszukaj hwasanGlobalOptions) lub w środowisku procesu (aby zobaczyć bieżące ustawienia, wpisz adb shell echo $HWASAN_OPTIONS).

Ten błąd może też wystąpić, jeśli dostępna pamięć nie jest mapowana lub została przydzielona przez alokator, który nie obsługuje HWASan. W takim przypadku tag mem wymieniony w nagłówku awarii jest zwykle równy 00. Jeśli masz dostęp do pełnego zrzutu, może się przydać sprawdzenie zrzutu map pamięci, aby dowiedzieć się, do którego mapowania (jeśli w ogóle) należy adres.

Zagnieżdżony błąd w tym samym wątku

Oznacza to, że podczas generowania raportu o awarii HWASan wystąpił błąd. Zwykle jest to spowodowane błędem w środowisku wykonawczym HWASan. Zgłoś błąd i, jeśli to możliwe, podaj instrukcje dotyczące odtworzenia problemu.