Debugowanie i eliminowanie błędów pamięci

Android obsługuje wiele narzędzi do debugowania błędów pamięci. Każda z nich ma swoje wady i zalety, więc przeczytaj poniższe informacje, aby zdecydować, która z nich jest najlepsza w Twoim przypadku. W tym dokumencie znajdziesz omówienie dostępnych narzędzi, dzięki czemu możesz zdecydować, które z nich chcesz dokładniej poznać. Jest on jednak dość zwięzły, więc szczegółowe informacje znajdziesz w dokumentacji poszczególnych narzędzi.

tl;dr

Języki bezpieczne pod względem zarządzania pamięcią

Język bezpieczny pod względem zarządzania pamięcią to jedyny sposób na całkowite uniknięcie błędów związanych z pamięcią i ich ograniczenie. Pozostałe narzędzia na tej stronie mogą pomóc w zwiększeniu bezpieczeństwa i niezawodności kodu, który nie jest bezpieczny pod względem pamięci, ale użycie języka bezpiecznego pod względem pamięci eliminuje całą klasę problemów.

Oficjalnie obsługiwane języki bezpieczne pod względem pamięci w Androidzie to Java i Kotlin. Większość aplikacji na Androida łatwiej jest tworzyć w jednym z tych języków.

Niektórzy deweloperzy aplikacji dostarczają kod napisany w języku Rust, a jeśli czytasz tę stronę, prawdopodobnie masz dobry powód, aby potrzebować kodu natywnego (przenośność, wydajność lub jedno i drugie). Rust to najlepszy wybór w przypadku bezpiecznego pod względem pamięci kodu natywnego na Androidzie. Jeśli zdecydujesz się na to rozwiązanie, zespół NDK niekoniecznie będzie w stanie Ci pomóc w rozwiązaniu problemów, ale chętnie się o nich dowie.

PAC/BTI

Pointer Authentication and Branch Target Identification, znane też jako PAC/BTI, to narzędzia łagodzące, które można stosować w środowisku produkcyjnym. Chociaż są to oddzielne technologie, są one kontrolowane przez tę samą flagę kompilatora, więc są zawsze używane razem.

Te funkcje są zgodne wstecznie z urządzeniami, które ich nie obsługują, ponieważ nowe instrukcje są na starszych urządzeniach operacjami bezczynnymi. Konieczne jest też posiadanie odpowiednio nowego jądra i odpowiednio nowej wersji systemu operacyjnego. Sprawdzenie, czy w /proc/cpuinfo występuje pacabti, pozwala określić, czy masz wystarczająco nowy sprzęt i jądro. Android 12 (API 31) ma niezbędną obsługę przestrzeni użytkownika.

Zalety:

  • Można ją włączyć we wszystkich kompilacjach bez powodowania problemów na starszych urządzeniach lub jądrach (ale upewnij się, że została przetestowana na urządzeniu, jądrze lub systemie operacyjnym, które obsługują tę funkcję).

Wady:

  • Dostępne tylko w przypadku aplikacji 64-bitowych
  • Nie zapobiega błędom na urządzeniach, które nie obsługują tej funkcji
  • 1% narzutu na rozmiar kodu

GWP-Asan

GWP-ASan może służyć do wykrywania błędów pamięci w terenie, ale częstotliwość próbkowania jest zbyt niska, aby skutecznie im zapobiegać.

Zalety:

  • Brak znaczącego obciążenia procesora lub pamięci
  • Łatwe wdrażanie: nie wymaga ponownego kompilowania kodu natywnego
  • Działa w przypadku aplikacji 32-bitowych

Wady:

  • Niska częstotliwość próbkowania wymaga dużej liczby użytkowników, aby skutecznie znajdować błędy.
  • Wykrywa tylko błędy sterty, a nie błędy stosu.

HWASan

Sprzętowy moduł sprawdzania adresów pamięci, znany też jako HWASan, najlepiej nadaje się do wykrywania błędów pamięci podczas testowania. Jest to najbardziej przydatne w przypadku testów automatycznych, zwłaszcza testów fuzzingowych, ale w zależności od wymagań aplikacji dotyczących wydajności może być też używane na telefonach z wyższej półki w ustawieniach testowych.

Zalety:

  • Brak wyników fałszywie pozytywnych
  • Wykrywa dodatkowe klasy błędów, których ASan nie może wykryć (użycie stosu po powrocie).
  • Mniejszy odsetek fałszywie negatywnych wyników niż w przypadku MTE (1 na 256 w porównaniu z 1 na 16)
  • Mniejsze obciążenie pamięci niż w przypadku ASan, najbliższej alternatywy

Wady:

  • Znaczne obciążenie procesora (ok. 100%), rozmiaru kodu (ok. 50%) i pamięci (10–35%).
  • Do API 34 i NDK r26 wymagane jest wgranie obrazu zgodnego z HWASan.
  • Działa tylko w przypadku aplikacji 64-bitowych

MTE

Memory Tagging Extension, czyli MTE, to tańsza alternatywa dla HWASan. Oprócz funkcji debugowania i testowania można go używać do wykrywania i ograniczania uszkodzeń pamięci w wersji produkcyjnej. Jeśli masz sprzęt do testowania kompilacji MTE, włącz tę funkcję.

Zalety:

  • Wystarczająco mały narzut, aby można go było tolerować w wersji produkcyjnej wielu aplikacji
  • Brak wyników fałszywie pozytywnych
  • Nie wymaga ponownego kompilowania kodu w celu wykrywania błędów sterty (ale wymaga tego w przypadku błędów stosu)

Wady:

  • W 2024 r. nie ma dostępnych w sprzedaży urządzeń z domyślnie włączoną technologią MTE, ale w dokumentacji firmy Arm można znaleźć informacje o tym, jak włączyć MTE do testowania na telefonach Pixel 8 i Pixel 8 Pro.
  • Współczynnik wyników fałszywie negatywnych 1:16 w porównaniu z 1:256 w przypadku HWASan
  • Dostępne tylko w przypadku aplikacji 64-bitowych
  • Wymaga utworzenia osobnych bibliotek do kierowania reklam na urządzenia z włączoną i wyłączoną funkcją MTE

ASan

Address Sanitizer, znany też jako ASan, to najstarsze i najbardziej rozpowszechnione z dostępnych narzędzi. Jest przydatne do wykrywania błędów pamięci podczas testowania i debugowania problemów, które występują tylko na starszych urządzeniach, na których nie są dostępne żadne inne narzędzia. W miarę możliwości preferuj HWASan.

Zalety:

  • Powszechnie dostępne. Może działać na urządzeniach z Androidem w wersji KitKat
  • Brak fałszywie pozytywnych lub negatywnych wyników, jeśli jest używany prawidłowo

Wady:

  • Trudność w prawidłowym tworzeniu i pakowaniu
  • Największy narzut ze wszystkich opcji: ok. 100% CPU, ok. 50% rozmiaru kodu, ok. 100% wykorzystania pamięci.
  • Wersja nie jest już obsługiwana
  • Zawiera znane błędy, które nie zostaną naprawione