Freigeben über


AddressSanitizer runtime

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. For more information, see the section on linking in the AddressSanitizer language, build, and debugging reference.

When compiling with cl /fsanitize=address, the compiler generates instructions to manage and check shadow bytes. 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 Fehlerdiagnosen 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).

Note

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.

Previous versions

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 DEBUG? ASan-Bibliothek (.lib) ASan-Laufzeit-Binärdatei (.dll)
/MT EXE No clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch} None
/MT DLL No clang_rt.asan_dll_thunk-{arch} None
/MD Either No clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MT EXE Yes clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch} None
/MT DLL Yes clang_rt.asan_dbg_dll_thunk-{arch} None
/MD Either Yes 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.

Function interception

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. These shadow bytes allow the compiler-generated checks of the shadow bytes to determine whether a load or store is valid.

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.

Note

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, malloc/free, ,new/deleteHeapAlloc/HeapFree (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. This API enables these allocators to function properly with the existing AddressSanitizer runtime and shadow byte conventions.

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)

Note

Wenn Sie den Speicher manuell vergiften, müssen Sie es aufheben, bevor Sie es wiederverwenden. Dies ist besonders wichtig für Stapeladressen, z. B. für eine lokale Variable, die während der Programmausführung häufig wiederverwendet werden. Sie riskieren, falsch positive Ergebnisse in manuell vergifteten Stapeladressen einzuführen use-after-poison , wenn Sie sie nicht entpacken, bevor ihr Stapelrahmen entfernt wird.

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.

Runtime options

Der MSVC AddressSanitizer basiert auf der Clang AddressSanitizer-Laufzeit aus dem llvm-Projekt-Repository. Aus diesem Gründen stehen auch die meisten ASan-Laufzeitoptionen von Clang in MSVC zur Verfügung. 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.

Konfigurieren von Laufzeitoptionen

ASan-Laufzeitoptionen werden auf eine von zwei Arten festgelegt:

  • Die ASAN_OPTIONS-Umgebungsvariable
  • Die __asan_default_options Benutzerfunktion

Wenn die Umgebungsvariable und die Benutzerfunktion widersprüchliche Optionen angeben, haben die Optionen in der ASAN_OPTIONS Umgebungsvariable Vorrang.

Es werden mehrere Optionen angegeben, indem sie durch einen Doppelpunkt (:) getrennt werden.

Im folgenden Beispiel wird eine und alloc_dealloc_mismatch null festgelegtsymbolize:

set ASAN_OPTIONS=alloc_dealloc_mismatch=1:symbolize=0

Oder fügen Sie der Codefunktion die folgende Funktion hinzu:

extern "C" const char* __asan_default_options()
{
  return "alloc_dealloc_mismatch=1:symbolize=0";
}

Nicht unterstützte AddressSanitizer-Optionen

  • detect_container_overflow
  • unmap_shadow_on_exit

Note

Die AddressSanitizer-Laufzeitoption halt_on_error funktioniert nicht wie erwartet. In both the Clang and the MSVC runtime libraries, many error types are considered non-continuable, including most memory corruption errors.

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

MSVC-spezifische AddressSanitizer-Laufzeitoptionen

  • continue_on_error Boolescher Wert, der standardmäßig auf false festgelegt ist. Bei Festlegung auf true, ermöglicht es dem Programm, die Ausführung fortzusetzen, nachdem eine Speicherverletzung gemeldet wurde, sodass Sie mehrere Fehlerberichte sammeln können.

  • 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.

Note

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.

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

    Note

    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.

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.

Default interceptors

Optional 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

See also

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