Speicherbeschädigung mit Address Sanitizer beheben

In diesem Dokument erfahren Sie, wie Sie spezielle Debugging-Tools bei der Verwendung von AGDE aktivieren. Diese Tools können bei schwer zu diagnostizierenden Speicherbeschädigungen und Überschreibfehlern helfen.

HWAddress Sanitizer und Address Sanitizer

HWAddress Sanitizer (HWASan) und AddressSanitizer (ASan) sind Tools zum Beheben von Speicherbeschädigungen, die bei der Behebung von Speicherbeschädigungen und Überschreibungsfehlern helfen, z. B.:

  • Stack-Pufferüberläufe und -Unterläufe
  • Heap-Pufferüberläufe und ‑Unterläufe
  • Verwendung des Stacks außerhalb seines Gültigkeitsbereichs
  • Fehler vom Typ „Double free“ und „Wild free“
  • Stacknutzung nach Rückgabe (nur HWASan)

Wir empfehlen, HWASan oder ASan nur zu aktivieren, wenn Sie ein Problem beheben oder automatisierte Tests durchführen. Diese Tools sind zwar leistungsstark, ihre Verwendung führt jedoch zu einer Strafzahlung.

Laufzeitverhalten

Wenn diese Option aktiviert ist, prüfen sowohl HWASan als auch ASan automatisch auf Speicherbeschädigungen in Ihrer App.

Wenn ein Speicherfehler erkannt wird, stürzt die App mit dem Fehler SIGBART (Signalabbruch) ab und druckt eine detaillierte Meldung in logcat aus. Eine Kopie der Nachricht wird auch in eine Datei unter /data/tombstones geschrieben.

Die Fehlermeldung sieht in etwa so aus:

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)

Voraussetzungen

HWASan-Anforderungen

So verwenden Sie HWASan:

  • Sie müssen AGDE 24.1.99 oder höher verwenden.
  • Die App muss mit NDK 26 oder höher erstellt werden.
  • Die App muss mit dem Ziel-SDK 34 oder höher erstellt werden.
  • Das Ziel muss ein arm64-v8a-Gerät mit Android 14 (API-Level 34) oder höher sein.

Gemeinsam genutzte C++-Standardbibliothek in Ihrem Projekt verwenden

Aufgrund eines bekannten Problems ist ASan bei Verwendung von libc++_static nicht mit der C++-Ausnahmebehandlung kompatibel. Bei der Verwendung von libc++_shared tritt dieses Problem nicht auf.

HWASan hat eine eigene Implementierung der Operatoren new und delete, die nicht verwendet werden kann, wenn die Standardbibliothek statisch mit dem Projekt verknüpft ist.

Informationen zum Ändern dieser Einstellung finden Sie im Abschnitt C++-Standardbibliothek verknüpfen dieses Dokuments.

Generierung von Frame Pointer aktivieren

HWASan und ASan verwenden einen schnellen Frame-Pointer-basierten Unwinder, um Informationen zum Stack-Trace für Speicherallokations- und -delokationsereignisse zu generieren. Das bedeutet, dass Sie die Generierung von Framepointern in den C++-Compilereinstellungen aktivieren müssen, um diese Funktionen zu verwenden. Sie müssen also die Optimierung des Auslassens von Framepointern deaktivieren.

Informationen zum Ändern dieser Einstellung finden Sie in diesem Dokument im Abschnitt Generierung von Frame Pointer aktivieren.

Visual Studio-Projekt für die Verwendung von HWASan oder ASan konfigurieren

HWASan oder ASan aktivieren

Wenn Sie HWASan oder ASan aktivieren möchten, rufen Sie auf der Seite Property-Seiten für Ihr Projekt die Option Konfigurationseigenschaften > Allgemein auf.

Das Eigenschaftenmenü des Visual Studio-Solution Explorers für das aktuelle Projekt.

Abbildung 1: Die Option Properties (Eigenschaften) des Projekts im Visual Studio-Fenster „Solution Explorer“

Das Dialogfeld „Property-Seiten des Projekts“ mit den allgemeinen Eigenschaften und den hervorgehobenen Einstellungen für die Adressenbereinigung

Abbildung 2: Die Einstellung Address Sanitizer (ASan) in den allgemeinen Projekteigenschaften.

Wenn Sie HWASan für Ihr Projekt aktivieren möchten, ändern Sie die Einstellung Address Sanitizer (ASan) in Hardware ASan Enabled (fsanitize=hwaddress).

Wenn Sie ASan für Ihr Projekt aktivieren möchten, ändern Sie die Einstellung Address Sanitizer (ASan) in ASan Enabled (fsanitize=address).

Generierung von Frame Pointer aktivieren

Die Generierung von Frame Pointern wird durch die C/C++-Compilereinstellung Omit Frame Pointer gesteuert. Sie finden sie auf den Property-Seiten Ihres Projekts unter Konfigurationseigenschaften > C/C++ > Optimierung.

Das Dialogfeld „Property-Seiten des Projekts“ mit den Eigenschaften für die C/C++-Optimierung und den hervorgehobenen Einstellungen für den Auslassungs-Frame-Pointer

Abbildung 3: Speicherort der Einstellung Omit Frame Pointer

Wenn Sie HWASan oder ASan verwenden, setzen Sie die Einstellung Omit Frame Pointer auf No (-fno-omit-frame-pointer).

C++-Standardbibliothek im Modus „Gemeinsam genutzte Bibliothek“ verknüpfen

Die Einstellung für den Linker-Modus der C++-Standardbibliothek finden Sie auf den Property-Seiten Ihres Projekts unter Konfigurationseigenschaften > Allgemein im Abschnitt Projektstandardwerte.

Das Dialogfeld „Property-Seiten des Projekts“ mit der ausgewählten Kategorie „Allgemein“ und der hervorgehobenen Einstellung „Verwendung von STL“

Abbildung 4: Speicherort der Einstellung für den Linker-Modus der C++-Standardbibliothek

Wenn Sie HWASan oder ASan verwenden, legen Sie für Use of STL (STL verwenden) die Option Use C++ Standard Libraries (.so) (C++-Standardbibliotheken (.so) verwenden) fest. Mit diesem Wert wird die C++-Standardbibliothek als freigegebene Bibliothek mit Ihrem Projekt verknüpft. Dies ist erforderlich, damit HWASan und ASan ordnungsgemäß funktionieren.

Build-Konfiguration für die Verwendung von Address Sanitizer erstellen

Wenn Sie HWASan oder ASan vorübergehend verwenden möchten, sollten Sie nicht nur zu diesem Zweck eine neue Buildkonfiguration erstellen. Das kann der Fall sein, wenn Ihr Projekt klein ist, Sie die Funktion ausprobieren oder auf ein Problem reagieren, das Sie während des Tests feststellen.

Wenn Sie es jedoch für nützlich halten und regelmäßig verwenden möchten, können Sie eine neue Build-Konfiguration für HWASan oder ASan erstellen, wie im Teapot-Beispiel gezeigt. Das kann beispielsweise der Fall sein, wenn Sie Address Sanitizer regelmäßig als Teil Ihrer Unit-Tests oder während nächtlicher Smoke-Tests Ihres Spiels ausführen.

Das Erstellen einer separaten Build-Konfiguration kann besonders nützlich sein, wenn Sie ein großes Projekt mit einer großen Anzahl verschiedener Drittanbieterbibliotheken haben, die Sie normalerweise statisch mit der C++-Standardbibliothek verknüpfen. Spezielle Build-Konfigurationen können dazu beitragen, dass Ihre Projekteinstellungen immer korrekt sind.

Wenn Sie eine Buildkonfiguration erstellen möchten, klicken Sie auf den Tab Eigenschaften Ihres Projekts und dann auf die Schaltfläche Konfigurationsmanager…. Öffnen Sie dann das Drop-down-Menü Aktive Lösungskonfiguration. Wählen Sie dann aus und erstellen Sie eine neue Buildkonfiguration mit einem geeigneten Namen, z. B. HWASan enabled.

HWASan mit benutzerdefinierten Speicherallokatoren verwenden

HWASan fängt automatisch den über malloc (oder new) zugewiesenen Arbeitsspeicher ab, damit Tags in Zeiger eingefügt und auf Tag-Abweichungen geprüft werden können.

Bei Verwendung eines benutzerdefinierten Speicherallokators kann HWASan Ihre benutzerdefinierten Speicherallokationsmethoden jedoch nicht automatisch abfangen. Wenn Sie HWASan mit Ihrem benutzerdefinierten Speicherallokator verwenden möchten, müssen Sie Ihren Speicherallokator so instrumentieren, dass er HWASan explizit aufruft. Das ist mit nur wenigen Codezeilen möglich.

Voraussetzungen

Die HWASan-Methoden, die du aufrufen musst, sind in diesem Header definiert:

#include "sanitizer/hwasan_interface.h"

Speicherzuweisung erfassen

  1. Weisen Sie Objekte mit einer Blockgranularität und ‑ausrichtung von 16 Byte zu. Wenn Sie beispielsweise einen Pool-Allocator haben, der Objekte mit einer festen Größe von 24 Byte bereitstellt, runden Sie Ihre Zuweisungen auf 32 Byte auf und binden Sie sie auf 16 Byte.

  2. Erstellen Sie ein 8‑Bit-Tag. Die Werte 0–16 dürfen nicht verwendet werden, da sie für die interne Verwendung reserviert sind.

  3. Aktivieren Sie HWASan, um mit diesem Tag die Speicherregion zu erfassen:

    __hwasan_tag_memory((void*) address, tag, size);
    
  4. Führen Sie das Tag in die oberen 8 Bit Ihres Cursors ein:

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

Methode zur Speicherfreigabe instrumentieren

  1. Setzen Sie das Tag für den Speicherbereich zurück, damit weitere Zugriffe über die vorhandenen getaggten Zeiger fehlschlagen:

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

Mit einem vorab zugewiesenen Objektpool arbeiten

Wenn Ihr Speicherallokator Objekte in einem Pool vorab zuweist und Objekte zurück in den Pool gibt, anstatt sie tatsächlich freizugeben, kann Ihre Methode zur Speicherfreigabe das Tag für den Speicher und den Zeiger direkt mit einem neuen Wert überschreiben:

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

Bei dieser Methode müssen Ihre Zuweisungsmethoden keine Zeiger oder Speicherblöcke taggen, sondern die Zeiger und Speicherblöcke, wenn Sie die Objekte in Ihrem Pool vorab zuweisen. Im Beispiel für PoolAllocator wird dieser Stil verwendet.