Freigeben über


AddressSanitizer-Schattenbytes

Wir fassen kurz das Konzept von Schattenbytes zusammen und wie sie von der Laufzeitimplementierung /fsanitize=addressverwendet werden können. Weitere Details finden Sie in der anfänglichen Forschungsdokumentation AddressSanitizer - Serebryany, et al und der aktuellen AddressSanitizer-Algorithmusdokumentation.

Kernkonzept

Alle 8 Bytes im virtuellen Adressraum Ihrer Anwendung können mithilfe eines Schattenbytes beschrieben werden.

Ein Schattenbyte beschreibt, wie viele Bytes derzeit wie folgt zugänglich sind:

  • 0 bedeutet alle 8 Byte
  • 1-7 bedeutet ein bis sieben Bytes
  • Negative Zahlen codieren den Kontext für die Laufzeit, die für die Berichterstellungsdiagnose verwendet werden soll.

Schattenbytelegende

Betrachten Sie diese Schattenbytelegende, in der alle negativen Zahlen definiert sind:

Screenshot der AddressSanitizer-Schatten-Byte-Legende.

Zuordnung – Beschreiben des Adressraums

Alle 8 Bytes im virtuellen Adressraum der Anwendung, der "0-mod-8" ausgerichtet ist, können dem Schattenbyte zugeordnet werden, das diesen Platz im virtuellen Adressbereich beschreibt. Diese Zuordnung kann mit einer einfachen Schicht erreicht und hinzugefügt werden.

Auf x86:

char shadow_byte_value = *((Your_Address >> 3) + 0x30000000)

Auf x64:

char shadow_byte_value = *((Your_Address >> 3) + _asan_runtime_assigned_offset)

Codegenerierung – Tests

Überlegen Sie, wie bestimmte Schattenbytes entweder durch den vom Compiler generierten Code, statische Daten oder die Laufzeit geschrieben werden. Dieser Pseudocode zeigt, wie es möglich ist, eine Prüfung zu generieren, die vor jedem Laden oder Speichern steht:

ShadowAddr = (Addr >> 3) + Offset;
if (*ShadowAddr != 0) {
    ReportAndCrash(Addr);
}

Bei der Instrumentierung eines Speicherverweises, der weniger als 8 Byte breit ist, ist die Instrumentierung etwas komplexer. Wenn der Schattenwert positiv ist (d. h. nur die ersten k Bytes im 8-Byte-Wort können zugegriffen werden), müssen wir die letzten 3 Bits der Adresse mit k vergleichen.

ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k)) {
    ReportAndCrash(Addr);
}

Die Laufzeit und der vom Compiler generierte Code schreiben beide Schattenbytes. Diese Schattenbytes erlauben oder widerrufen den Zugriff, wenn Bereiche enden oder Speicher freigegeben werden. Die obigen Überprüfungen lesen Schattenbytes, die 8-Byte-"Slots" im Adressraum Ihrer Anwendung zu einem bestimmten Zeitpunkt in der Ausführung des Programms beschreiben. Neben diesen explizit generierten Prüfungen überprüft die Laufzeit auch Schattenbytes, nachdem sie viele Funktionen im CRT abfangen (oder "Hooks").

Weitere Informationen finden Sie in der Liste der abgefangenen Funktionen.

Festlegen von Schattenbytes

Sowohl der Vom Compiler generierte Code als auch die AddressSanitizer-Laufzeit können Schattenbytes schreiben. Der Compiler kann z. B. Schattenbytes festlegen, um den Zugriff auf lokale Stapel mit fester Größe zu ermöglichen, die in einem inneren Bereich definiert sind. Die Laufzeit kann globale Variablen im Datenabschnitt mit Schattenbytes umgeben.

Siehe auch

AddressSanitizer -Übersicht
Beheben bekannter Probleme mit demSanitizer
AddressSanitizer Build- und Sprachreferenz
AddressSanitizer-Laufzeitreferenz
AddressSanitizer-Cloud oder verteilte Tests
AddressSanitizer Debugger-Integration
Beispiele für AddressSanitizer-Fehler