Gdy narzędzie HWASan wykryje błąd pamięci, proces jest zamykany za pomocą funkcji abort()
, a raport jest drukowany w stderr i logcat. Podobnie jak wszystkie natywne awarie na Androidzie, błędy HWASan są uwzględnione w sekcji /data/tombstones
.
Przykładowy raport
W odróżnieniu od zwykłych awarii natywnych HWASan zawiera dodatkowe informacje w polu Abort message (Anuluj komunikat) u góry nagłówka. Oto przykładowy błąd powodowany przez stos. Informacje o błędach w kodzie źródłowym znajdziesz w notatce dotyczącej sekcji dotyczących kodu źródłowego.
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 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: '==9569==ERROR: HWAddressSanitizer: tag-mismatch on address 0x00433ae20045 at pc 0x00623ae2a9cc READ of size 1 at 0x00433ae20045 tags: 5b/83 (ptr/mem) in thread T0 #0 0x7240450c68 (/system/lib64/vndk-sp-R/libcutils.so+0x8c68) #1 0x723dffd490 (/vendor/lib64/sensors.ssc.so+0x34490) #2 0x723e0126e0 (/vendor/lib64/sensors.ssc.so+0x496e0) [...] [0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5 Cause: use-after-free 0x00433ae20045 is located 5 bytes inside of 10-byte region [0x00433ae20040,0x00433ae2004a) freed by thread T0 here: #0 0x72404d1b18 (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x10b18) #1 0x723af23040 (/vendor/lib64/libgralloccore.so+0x5040) #2 0x723af23fa4 (/vendor/lib64/libgralloccore.so+0x5fa4) [...] previously allocated here: #0 0x72404ce554 (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0xd554) #1 0x7240115654 (/apex/com.android.runtime/lib64/bionic/libc.so+0x43654) #2 0x7240450ac8 (/system/lib64/vndk-sp-R/libcutils.so+0x8ac8) [...] hwasan_dev_note_heap_rb_distance: 1 1023 hwasan_dev_note_num_matching_addrs: 0 hwasan_dev_note_num_matching_addrs_4b: 0 Thread: T0 0x006a00002000 stack: [0x007fc1064000,0x007fc1864000) sz: 8388608 tls: [0x00737702ffc0,0x007377033000) Memory tags around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x006f33ae2000: 08 00 08 00 [83] 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Tags for short granules around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1ff0: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. =>0x006f33ae2000: 72 .. d0 .. [..] .. .. .. .. .. .. .. .. .. .. .. 0x006f33ae2010: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags Registers where the failure occurred (pc 0x00623ae2a9cc): x0 0000007fc18623ec x1 5b0000433ae20045 x2 0000000000000013 x3 ffffffffffffffff x4 ffffffffffffffff x5 0000007fc1861da3 x6 6f7420676e696f47 x7 45522061206f6420 x8 0000000000000000 x9 0200006b00000000 x10 00000007fc18623f x11 5b0000433ae20040 x12 6f64206f7420676e x13 0a44414552206120 x14 0000000000000010 x15 ffffffffffffffff x16 000000737169ac94 x17 0000000000000007 x18 0000007377bd8000 x19 0000007fc1862498 x20 0200006b00000000 x21 0000007fc18624a8 x22 0000000000000001 x23 0000000000000000 x24 0000000000000000 x25 0000000000000000 x26 0000000000000000 x27 0000000000000000 x28 0000000000000000 x29 0000007fc1862410 x30 000000623ae2a9d0 sp 0000007fc18623d0 SUMMARY: HWAddressSanitizer: tag-mismatch (/system/lib64/vndk-sp-R/libcutils.so+0x8c68) [ … regular crash dump follows …]
Jest to podobne do raportu AddressSanitizer. W przeciwieństwie do nich 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ć:
- Dostęp poza zakres stosu lub stosu dynamicznego
- Błąd „use-after-free” w stercie
- Błąd „use-after-return” na stosie
Sekcje
Poniżej znajdziesz wyjaśnienie poszczególnych sekcji raportu HWASan.
Błąd dostępu
Zawiera informacje o nieprawidłowym dostępie do pamięci, w tym:
- Typ dostępu (
READ
lubWRITE
) - Rozmiar dostępu (ile bajtów zostało odczytanych)
- Numer wątku dostępu
- tagi wskaźnika i pamięci (do zaawansowanego debugowania).
Dostęp do ścieżki śledzenia
Zrzut stosu z informacjami o nieprawidłowym dostępie do pamięci. Aby dowiedzieć się więcej o symbolizacji, zapoznaj się z artykułem Symbolizacja.
Przyczyna
Możliwa przyczyna nieprawidłowego dostępu. Jeśli jest ich więcej, są one wymienione w kolejności malejącej prawdopodobieństwa. Poprzedza szczegółowe informacje o potencjalnej przyczynie. HWASan może zdiagnozować te przyczyny:
- Używanie po zakończeniu okresu bezpłatnego
- niezgodność tagu stosu, która może być spowodowana użyciem stosu po instrukcji return, użyciem stosu po zakresie lub wyjściem poza zakres.
- Przepełnienie bufora stosu
- Global overflow
Informacje o pamięci
Opisuje, co HWASan wie o pamięci, do której uzyskuje dostęp. Może się to różnić w zależności od typu błędu:
Typ błędu | Przyczyna | Format raportu |
---|---|---|
Niezgodność tagu | Używanie po zakończeniu okresu bezpłatnego | 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 stosu | Pamiętaj, że może to być też przepełnienie.<address> is located N bytes to the right of M-byte region [<start>, <end>) allocated here: |
|
Niezgodność tagu stosu | Raporty stosu nie rozróżniają błędów przepełnienia, niedopełnienia i użycia po powrocie. Dodatkowo, aby znaleźć alokację stosu, która jest źródłem błędu, wymagany jest krok symbolizacji offline. Zobacz Informacje o raportach z warstw. | |
Nieprawidłowy wolny | Używanie po okresie bezpłatnym | Błąd podwójnego zwolnienia. Jeśli tak się dzieje podczas zamykania procesu, może to oznaczać naruszenie zasad rozwiązywania sporów online.
<address> is located N bytes inside of M-byte region [<start>, <end>) freed by thread T0 here: |
Nie można opisać adresu | Albo wolna pamięć (wolna pamięć, która nie została wcześniej przydzielona), albo podwójna wolna pamięć po usunięciu przydzielonej pamięci z wolnego bufora HWASan. | |
0x... to pamięć cienia HWAsan | A wild free, ponieważ aplikacja próbowała zwolnić pamięć wewnętrzną HWASan. |
Zrzut stosu dotyczący zwalniania zasobów
śledzenie zrzutu stosu, gdzie pamięć została zwolniona; Widoczne tylko w przypadku błędów typu use-after-free lub invalid-free. Aby dowiedzieć się, jak to zrobić, przeczytaj artykuł Symbolizacja.
Zrzut stosu alokacji
śledzenie zrzutu stosu, gdzie pamięć została przydzielona; Aby dowiedzieć się, jak to zrobić, przeczytaj artykuł Symbolizacja.
Zaawansowane informacje o debugowaniu
Raport HWASan zawiera też informacje o zaawansowanym debugowaniu, w tym (w podanej kolejności):
- Lista wątków w procesie
- Lista wątków w procesie
- Wartość tagów pamięci w pobliżu pamięci z błędem
- zrzut rejestrów w miejscu dostępu do pamięci,
Zrzut danych tagu pamięci
Dump pamięci tagu umożliwia znalezienie w pobliżu przydziałów pamięci z tym samym tagiem co tag wskaźnika. Te tagi mogą wskazywać na dostęp poza zakresem z dużym przesunięciem. Jeden tag odpowiada 16 bajtom pamięci; tag wskaźnika to 8 najstarszych bitów adresu. Zrzut pamięci tagów może zawierać wskazówki. Na przykład 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ą 16, reszta jest przechowywana jako tag pamięci, a ten z kolei jako krótki tag granulkowy. W poprzednim przykładzie tuż po oznaczonym pogrubioną czcionką przypisie ad
mamy przypisany do tagu 5c
przydział o długości 5 × 16 + 4 = 84 bajty.
Tag pamięci o wartości 0 (np. tags: ad/00 (ptr/mem)
) wskazuje błąd polegający na użyciu stosu po powrocie.
Zrzut rejestru
Dane zrzutu rejestru w raportach HWASan odpowiadają instrukcji, która wykonała nieprawidłowy dostęp do pamięci. Po tym zrzucie się kolejny zrzut rejestru z normalnego modułu obsługi sygnałów Androida. Zignoruj drugi zrzut, ponieważ został wykonany, gdy HWASan wywołał funkcję abort()
i nie ma związku z błędem.
Symbolizacja
Aby uzyskać nazwy funkcji i numery wierszy w wyświetleniach stosu (oraz nazwy zmiennych w celu wykrywania błędów związanych z użyciem poza zakresem), konieczny jest krok symbolizacji offline.
Pierwsza konfiguracja: zainstaluj llvm-symbolizer
Aby to zilustrować, musisz mieć zainstalowany system llvm-symbolizer
i mieć do niego dostęp z poziomu $PATH
. W Debianie możesz go zainstalować za pomocą sudo apt install llvm
.
Pobieranie plików symboli
Do symbolizacji potrzebujemy binarnych plików z symbolami, które nie zostały pozbawione niepotrzebnych danych. Ich lokalizacja zależy od typu kompilacji:
- W przypadku kompilacji lokalnych pliki symboli znajdują się w katalogu
out/target/product/<product>/symbols/
. - W przypadku kompilacji AOSP (np. za pomocą narzędzia Android Flash Tool) kompilacje są dostępne w Android CI. W elementach kompilacji znajduje się plik
${PRODUCT}-symbols-${BUILDID}.zip
. - W przypadku wersji wewnętrznych z Twojej organizacji zapoznaj się z dokumentacją organizacji, aby uzyskać pomoc w pobieraniu plików symboli.
Symbolize
hwasan_symbolize --symbols <DECOMPRESSED_DIR>/out/target/product/*/symbols < crash
Interpretowanie raportów stosu
W przypadku błędów występujących w przypadku zmiennych stosu raport HWASan zawiera takie informacje:
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 ułatwić Ci analizowanie błędów stosu, HWASan śledzi poprzednie ramki stosu. HWASan nie przekształca ich w zrozumiałe dla człowieka treści w raporcie o błędzie i wymaga dodatkowego etapu symbolizacji.
Naruszenia zasad ODR
Niektóre błędy związane z możliwością korzystania z usługi po wygaśnięciu subskrypcji zgłoszone przez HWASan mogą wskazywać na naruszenie zasady jednej definicji (ODR). Naruszenie zasad dotyczących reklam na potrzeby pozyskiwania danych o użytkownikach ma miejsce, gdy ta sama zmienna jest zdefiniowana wielokrotnie w tym samym programie. Oznacza to też, że zmienna jest dekonstruowana wielokrotnie, co może prowadzić do błędu użycia po zwolnieniu.
Po symbolizacji naruszenia zasad ODR wskazują na błąd „use-after-free” z __cxa_finalize
, zarówno w nieprawidłowym dostępie do stosu, jak i w stosie freed here. Zaalokowana wcześniej tablica zawiera zmienną __dl__ZN6soinfo17call_constructorsEv
i powinna wskazywać miejsce w programie, w którym zdefiniowano zmienną wyżej w strukturze stosu.
Jeśli używasz bibliotek statycznych, możesz naruszyć zasady dotyczące ODR. Jeśli biblioteka statyczna, która definiuje zmienną globalną C++, jest połączona z wieloma bibliotekami współdzielczymi lub plikami wykonywalnymi, w tym samym zakresie adresów może istnieć wiele definicji tego samego symbolu, co powoduje błąd ODR.
Rozwiązywanie problemów
W tej sekcji opisujemy niektóre błędy i sposoby ich naprawiania.
HWAddressSanitizer nie może dokładniej opisać adresu
Czasami HWASan może zabraknąć miejsca na informacje o poprzednich przydziałach pamięci. W takim przypadku raport zawiera tylko jeden zrzut stosu dla bezpośredniego dostępu do pamięci, po którym następuje uwaga:
HWAddressSanitizer can not describe address in more detail.
W niektórych przypadkach możesz rozwiązać ten problem, wykonując test kilka razy. Inną opcją jest zwiększenie rozmiaru historii HWAS. Możesz to zrobić globalnie w build/soong/cc/sanitize.go
(szukaj hwasanGlobalOptions
) lub w środowisku procesu (spróbuj adb shell echo $HWASAN_OPTIONS
, aby wyświetlić bieżące ustawienia).
Ten błąd może też wystąpić, jeśli dostęp do pamięci nie jest mapowany lub jest przydzielany przez alokator, który nie jest świadomy HWAS. W takim przypadku tag mem
podany w nagłówku błędu jest zazwyczaj określony jako 00
. Jeśli masz dostęp do pełnego nagrobka, warto skorzystać z pliku z pamięcią map, aby dowiedzieć się, do którego mapowania (jeśli takie istnieje) należy adres.
Zagnieżdżony błąd w tym samym wątku
Oznacza to, że podczas generowania raportu o wypadku HWAS wystąpił błąd. Zwykle jest to spowodowane błędem w czasie wykonywania HWASan. Zgłoś błąd i w miarę możliwości podaj instrukcje odtwarzania problemu.