AddressSanitizer-Laufzeit

Die AddressSanitizer-Laufzeitbibliothek fängt allgemeine Speicherzuweisungsfunktionen und -vorgänge ab, um die Überprüfung von Speicherzugriffen zu ermöglichen. Es gibt mehrere verschiedene Laufzeitbibliotheken, die die verschiedenen Typen von ausführbaren Dateien unterstützen, die der Compiler generieren kann. Der Compiler und Linker verknüpfen automatisch die entsprechenden Laufzeitbibliotheken, solange Sie die /fsanitize=address Option zur Kompilierungszeit übergeben. Sie können das Standardverhalten überschreiben, indem Sie die /NODEFAULTLIB Option zur Linkzeit verwenden. Weitere Informationen finden Sie im Abschnitt zum Verknüpfen in der AddressSanitizer-Sprache, im Build- und Debugging-Verweis.

Beim Kompilieren mit cl /fsanitize=addressdem Compiler werden Anweisungen zum Verwalten und Überprüfen von Schattenbytes generiert. Ihr Programm verwendet diese Instrumentierung, um Speicherzugriffe auf den Stapel, im Heap oder im globalen Bereich zu überprüfen. Der Compiler erzeugt auch Metadaten zur Beschreibung von Stapel- und globalen Variablen. Mit diesen Metadaten kann die Laufzeit präzise Fehler Diagnose generieren: Funktionsnamen, Zeilen und Spalten im Quellcode. In Kombination können die Compilerüberprüfungen und Laufzeitbibliotheken viele Arten von Speichersicherheitsfehlern genau diagnostizieren, wenn sie zur Laufzeit aufgetreten sind.

Die Liste der Laufzeitbibliotheken zum Verknüpfen mit der AddressSanitizer-Laufzeit ab Visual Studio 17.7 Preview 3 folgt. Weitere Informationen zu den /MT Optionen (statisch verknüpfen die Laufzeit) und /MD (dynamisch verknüpfen sie den Redist zur Laufzeit) finden Sie unter /MD, /MT, /LD (Laufzeitbibliothek verwenden).

Hinweis

In der folgenden Tabelle {arch} ist entweder i386 oder x86_64. Diese Bibliotheken verwenden Clang-Konventionen für Architekturnamen. MSVC-Konventionen sind normalerweise x86 und x64 nicht i386 und x86_64, aber sie beziehen sich auf die gleichen Architekturen.

CRT-Option AddressSanitizer-Laufzeitbibliothek (.lib) Adresslaufzeit-Binärdatei (.dll)
/MT oder /MTd clang_rt.asan_dynamic-{arch}, clang_rt.asan_static_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MD oder /MDd clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}

Das folgende Diagramm zeigt, wie die Sprachlaufzeitbibliotheken für die /MTOptionen , /MTd, /MDund /MDd Compiler verknüpft sind:

Diagramm, wie die Laufzeitbibliotheken für verschiedene Compileroptionen verknüpft sind.

Die Abbildung zeigt drei Szenarien zum Verknüpfen der Laufzeitbibliothek. Der erste ist /MT oder /MTd. My_exe.exe und my_dll.dll werden beide mit ihren eigenen Kopien der statisch verknüpften VCRuntime-, Universal CRT- und C++-Laufzeiten angezeigt. Die Szenarien zeigen /MD, in denen sowohl my_exe.exe als auch my_dll.dll vcruntime140.dll, ucrtbase.dll und msvcp140.dll teilen. Das letzte Szenario zeigt /MDd, in dem sowohl my_exe.exe als auch my_dll.dll die Debugversionen der Laufzeiten gemeinsam nutzen: vcruntime140d.dll, ucrtbased.dll und msvcp140d.dll

Das folgende Diagramm zeigt, wie die ASan-Bibliothek für verschiedene Compileroptionen verknüpft ist:

Diagramm, wie die ASan-Laufzeit-DLL verknüpft ist.

Die Abbildung zeigt vier Szenarien zum Verknüpfen der ASan-Laufzeitbibliothek. Die Szenarien gelten für /MT (statisch verknüpfen die Laufzeit), /MTd (statisch die Debuglaufzeit verknüpfen), /MD (dynamisch den Redist zur Laufzeit verknüpfen), /MDd (dynamisch den Debug-Redist zur Laufzeit verknüpfen). In allen Fällen my_exe.exe Verknüpfungen und die zugehörigen verknüpfungen my_dll.dll mit einer einzelnen Instanz von clang-rt.asan-dynamix-x86_64.dll.

Auch wenn die Statischverknüpfung erfolgt, muss die ASan-Laufzeit-DLL zur Laufzeit vorhanden sein – im Gegensatz zu anderen C-Runtime-Komponenten.

Frühere Versionen

Vor Visual Studio 17.7 Preview 3 wurden statisch verknüpfte (/MT oder /MTd) Builds keine DLL-Abhängigkeit verwendet. Stattdessen wurde die AddressSanitizer-Laufzeit statisch mit der EXE des Benutzers verknüpft. DLL-Projekte würden dann Exporte aus der EXE des Benutzers laden, um auf die ASan-Funktionalität zuzugreifen.

Dynamisch verknüpfte Projekte (/MD oder /MDd) verwendeten unterschiedliche Bibliotheken und DLLs, je nachdem, ob das Projekt für das Debuggen oder Release konfiguriert wurde. Weitere Informationen zu diesen Änderungen und ihren Motivationen finden Sie unter MSVC Address Sanitizer – Eine DLL für alle Laufzeitkonfigurationen.

In der folgenden Tabelle wird das vorherige Verhalten der AddressSanitizer-Laufzeitbibliotheksverknüpfung vor Visual Studio 17.7 Preview 3 beschrieben:

CRT-Option DLL oder EXE DEBUGGEN? ASan-Bibliothek (.lib) ASan-Laufzeit-Binärdatei (.dll)
/MT EXE No clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch} Keine
/MT DLL No clang_rt.asan_dll_thunk-{arch} Keine
/MD Entweder No clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MT EXE Ja clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch} Keine
/MT DLL Ja clang_rt.asan_dbg_dll_thunk-{arch} Keine
/MD Sowohl als auch Ja clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch} clang_rt.asan_dbg_dynamic-{arch}

Das folgende Diagramm zeigt, wie die ASan-Bibliothek für verschiedene Compileroptionen vor Visual Studio 2022 17.7 Preview 3 verknüpft wurde:

Diagramm, wie die ASan-Laufzeit-DLL vor Visual Studio 2022 Preview 3 verknüpft wurde.

Die Abbildung zeigt vier Szenarien zum Verknüpfen der ASan-Laufzeitbibliothek. Die Szenarien gelten für /MT (statisch verknüpfen die Laufzeit), /MTd (statisch die Debuglaufzeit verknüpfen), /MD (dynamisch den Redist zur Laufzeit verknüpfen), /MDd (dynamisch den Debug-Redist zur Laufzeit verknüpfen). Für /MT verfügt my_exe.exe über eine statisch verknüpfte Kopie der ASan-Laufzeit. my_dll.dll Links zur ASan-Laufzeit in my_exe.exe. Bei /MTd ist das Diagramm identisch, mit der Ausnahme, dass es die statisch verknüpfte ASan-Laufzeit des Debugs verwendet. Bei /MD verknüpfen sowohl my_exe.exe als auch my_dll.dll mit der dynamisch verknüpften ASan-Laufzeit mit dem Namen clang_rt.asan_dynamic-x86_64.dll. Bei /MDd ist das Diagramm identisch, mit Ausnahme von my_exe.exe und my_dll.dll Verknüpfung mit der Debug-ASan-Laufzeit mit dem Namen clang_rt.asan_dbg_dynamic-x86_64.dll.

Funktionsinterception

Der AddressSanitizer erreicht funktionsübergreifende Abfangen durch viele Hotpatching-Techniken. Diese Techniken werden am besten im Quellcode selbst dokumentiert.

Die Laufzeitbibliotheken abfangen viele gängige Speicherverwaltungs- und Speichermanipulationsfunktionen ab. Eine Liste finden Sie unter AddressSanitizer-Liste der abgefangenen Funktionen. Die Zuordnungs-Interceptors verwalten Metadaten und Schattenbytes im Zusammenhang mit jedem Zuordnungsaufruf. Jedes Mal, wenn eine CRT-Funktion wie malloc oder delete aufgerufen wird, legen die Interceptors bestimmte Werte im AddressSanitizer-Schattenspeicherbereich fest, um anzugeben, ob diese Heap-Speicherorte derzeit zugänglich sind und welche Grenzen die Zuordnung sind. Mit diesen Schattenbytes können die vom Compiler generierten Überprüfungen der Schattenbytes bestimmen, ob eine Last oder ein Speicher gültig ist.

Das Abfangen ist nicht garantiert erfolgreich. Wenn eine Funktionsprologe zu kurz ist, um geschrieben jmp zu werden, kann das Abfangen fehlschlagen. Wenn ein Abhörfehler auftritt, löst das Programm ein debugbreak und hält an. Wenn Sie einen Debugger anfügen, wird die Ursache für das Abfangen klar. Wenn Sie dieses Problem haben, melden Sie einen Fehler.

Hinweis

Benutzer können optional versuchen, eine fehlgeschlagene Abfangen fortzusetzen, indem Sie die Umgebungsvariable ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE auf einen beliebigen Wert festlegen. Wenn sie über einen Abfangenfehler hinaus fortgesetzt werden, kann dies zu verpassten Fehlerberichten für diese Funktion führen.

Benutzerdefinierte Zuweisungen und die AddressSanitizer-Laufzeit

Die AddressSanitizer-Laufzeit stellt Interceptors für allgemeine Allocator-Schnittstellen, mallocfree/, ,/HeapFree/HeapAllocdeletenew (viaRtlAllocateHeap/RtlFreeHeap) bereit. Viele Programme verwenden benutzerdefinierte Allokatoren aus einem Grund oder einem anderen, ein Beispiel wäre ein beliebiges Programm, das oder dlmalloc eine Lösung mit der std::allocator Schnittstelle und VirtualAlloc(). Der Compiler kann einem benutzerdefinierten Zuweisungsvermerk nicht automatisch Schattenspeicherverwaltungsaufrufe hinzufügen. Es liegt in der Verantwortung des Benutzers, die bereitgestellte manuelle Vergiftungsschnittstelle zu verwenden. Diese API ermöglicht es diesen Allocators, ordnungsgemäß mit den vorhandenen AddressSanitizer-Laufzeit- und Schattenbytekonventionen zu funktionieren.

Manuelle AddressSanitizer-Vergiftungsschnittstelle

Die Benutzeroberfläche für die Optimierung ist einfach, sie legt jedoch Ausrichtungseinschränkungen für den Benutzer fest. Benutzer können diese Prototypen importieren, indem sie importiert sanitizer/asan_interface.hwerden. Hier sind die Prototypen der Schnittstellenfunktion:

void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);

Aus Gründen der Einfachheit stellt die Headerdatei der AddressSanitizer-Schnittstelle Wrappermakros bereit. Diese Makros überprüfen, ob die AddressSanitizer-Funktion während der Kompilierung aktiviert ist. Sie ermöglichen es Ihrem Quellcode, die Vergiftungsfunktionsaufrufe auszulassen, wenn sie nicht benötigt werden. Diese Makros sollten bevorzugt werden, um die oben genannten Funktionen direkt aufzurufen:

#define ASAN_POISON_MEMORY_REGION(addr, size)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)

Ausrichtungsanforderungen für AddressSanitizer-Vergiftungen

Jede manuelle Vergiftung von Schattenbytes muss die Ausrichtungsanforderungen berücksichtigen. Der Benutzer muss bei Bedarf Abstand hinzufügen, damit die Schattenbytes auf einer Bytegrenze im Schattenspeicher enden. Jedes Bit im AddressSanitizer-Schattenspeicher codiert den Zustand eines einzelnen Byte im Speicher der Anwendung. Diese Codierung bedeutet, dass die Gesamtgröße jeder Zuordnung einschließlich des Abstands an einer Grenze von 8 Byte ausgerichtet werden muss. Wenn die Ausrichtungsanforderung nicht erfüllt ist, kann dies zu einer falschen Fehlerberichterstattung führen. Die falsche Berichterstattung kann als fehlende Berichte (falsch negativ) oder Berichte zu Nichtfehlern (falsch positive Ergebnisse) manifestieren.

Eine Abbildung der Ausrichtungsanforderung und potenziellen Probleme finden Sie in den bereitgestellten ASan-Ausrichtungsbeispielen. Eines ist ein kleines Programm, um zu zeigen, was mit manueller Schattenspeichervergiftung schief gehen kann. Die zweite ist ein Beispiel für die Implementierung manueller Vergiftungen mit der std::allocator Schnittstelle.

Laufzeitoptionen

Microsoft C/C++ (MSVC) verwendet eine Laufzeit basierend auf der Clang AddressSanitizer-Laufzeit aus dem llvm-Projekt-Repository. Aus diesem Fall werden die meisten Laufzeitoptionen zwischen den beiden Versionen gemeinsam genutzt. Hier finden Sie eine vollständige Liste der öffentlichen Clang-Laufzeitoptionen. Wir dokumentieren einige Unterschiede in den folgenden Abschnitten. Wenn Sie Optionen entdecken, die nicht wie erwartet funktionieren, melden Sie einen Fehler.

Nicht unterstützte AddressSanitizer-Optionen

  • detect_container_overflow
  • unmap_shadow_on_exit

Hinweis

Die AddressSanitizer-Laufzeitoption halt_on_error funktioniert nicht wie erwartet. Sowohl in den Clang- als auch in den MSVC-Laufzeitbibliotheken gelten viele Fehlertypen als nicht kontinuierbar, einschließlich der meisten Speicherbeschädigungsfehler.

Weitere Informationen finden Sie im Abschnitt "Unterschiede mit Clang 12.0 ".

MSVC-spezifische AddressSanitizer-Laufzeitoptionen

  • windows_hook_legacy_allocatorsBoolescher Wert, der zum false Deaktivieren der Abfangen von und LocalAlloc Allokatoren GlobalAlloc festgelegt ist.

    Hinweis

    Die Option windows_hook_legacy_allocators war in der öffentlichen Llvm-Projektlaufzeit nicht verfügbar, als dieser Artikel geschrieben wurde. Die Option kann schließlich wieder zum öffentlichen Projekt beigetragen werden; Dies hängt jedoch von der Codeüberprüfung und der Akzeptanz der Community ab.

    Die Option windows_hook_rtl_allocators, zuvor ein Opt-In-Feature, während AddressSanitizer experimentell war, ist jetzt standardmäßig aktiviert. In Versionen vor Visual Studio 2022, Version 17.4.6, lautet falseder Standardwert . In Visual Studio 2022, Version 17.4.6 und höher, ist die Option windows_hook_rtl_allocators standardmäßig auf true.

  • iat_overwrite Zeichenfolge, standardmäßig auf "error" festgelegt. Andere mögliche Werte sind "protect" und "ignore". Einige Module überschreiben möglicherweise die import address table anderen Module, um Implementierungen bestimmter Funktionen anzupassen. Treiber stellen z. B. häufig benutzerdefinierte Implementierungen für bestimmte Hardware bereit. Die iat_overwrite Option verwaltet den Schutz der AddressSanitizer-Laufzeit vor Überschreibungen für bestimmte memoryapi.h Funktionen. Die Laufzeit verfolgt derzeit die VirtualAllocSchutzfunktionen VirtualProtect, und VirtualQuery die Funktionen. Diese Option ist in Visual Studio 2022, Version 17.5 Preview 1 und höher, verfügbar. Die folgenden iat_overwrite Werte steuern, wie die Laufzeit reagiert, wenn geschützte Funktionen überschrieben werden:

    • Bei Festlegung auf "error" (Standardeinstellung) meldet die Laufzeit immer dann einen Fehler, wenn ein Überschreiben erkannt wird.
    • Bei Festlegung auf "protect", versucht die Laufzeit, die Verwendung der überschriebenen Definition zu vermeiden und fortzufahren. Effektiv wird die ursprüngliche memoryapi Definition der Funktion innerhalb der Laufzeit verwendet, um unendliche Rekursion zu vermeiden. Andere Module im Prozess verwenden weiterhin die überschriebene Definition.
    • Bei Festlegung auf "ignore", versucht die Laufzeit nicht, überschriebene Funktionen zu korrigieren und mit der Ausführung fortzufahren.
  • windows_fast_fail_on_error Boolescher Wert (standardmäßig false) wird so festgelegt, dass true der Prozess nach dem Drucken des Fehlerberichts mit einem __fastfail(71) beendet werden kann.

Hinweis

Wenn abort_on_error Wert auf "true" festgelegt ist, wird das Programm unter Windows mit einem Exit(3) beendet. Um das aktuelle Verhalten nicht zu ändern, haben wir uns entschieden, stattdessen diese neue Option einzuführen. Wenn sowohl abort_on_error als auch windows_fast_fail_on_error wahr sind, wird das Programm mit dem __fastfail beendet.

AddressSanitizer-Liste der abgefangenen Funktionen (Windows)

Die AddressSanitizer-Laufzeit hotpatcht viele Funktionen, um Speichersicherheitsprüfungen zur Laufzeit zu ermöglichen. Hier ist eine nicht erschöpfende Liste der Funktionen, die die AddressSanitizer-Laufzeit überwacht.

Standardabschnitte

Optionale Interceptors

Die hier aufgeführten Interceptors werden nur installiert, wenn eine AddressSanitizer-Laufzeitoption aktiviert ist. Legen Sie diese Einstellung windows_hook_legacy_allocators fest, false um die Legacy-Allocator-Abfangen zu deaktivieren. set ASAN_OPTIONS=windows_hook_legacy_allocators=false

Weitere Informationen

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