Udostępnij przez


AddressSanitizer runtime

Biblioteka środowiska uruchomieniowego AddressSanitizer przechwytuje typowe funkcje alokacji pamięci i operacje umożliwiające inspekcję dostępu do pamięci. Istnieje kilka różnych bibliotek środowiska uruchomieniowego, które obsługują różne typy plików wykonywalnych, które mogą być generowane przez kompilator. Kompilator i konsolidator automatycznie łączą odpowiednie biblioteki środowiska uruchomieniowego, o ile opcja zostanie przekazana /fsanitize=address w czasie kompilacji. Domyślne zachowanie można zastąpić za pomocą /NODEFAULTLIB opcji w czasie połączenia. Aby uzyskać więcej informacji, zobacz sekcję dotyczącą łączenia w języku AddressSanitizer, kompilacji i debugowaniu.

Podczas kompilowania za pomocą cl /fsanitize=addressprogramu kompilator generuje instrukcje dotyczące zarządzania bajtami w tle i sprawdzania ich. Program używa tej instrumentacji do sprawdzania dostępu do pamięci na stosie, w stercie lub w zakresie globalnym. Kompilator tworzy również metadane opisujące stos i zmienne globalne. Te metadane umożliwiają środowisku uruchomieniowemu generowanie dokładnej diagnostyki błędów: nazwy funkcji, wiersze i kolumny w kodzie źródłowym. W połączeniu kompilator sprawdza i biblioteki środowiska uruchomieniowego można dokładnie zdiagnozować wiele typów usterek bezpieczeństwa pamięci, jeśli wystąpią w czasie wykonywania.

Poniżej znajduje się lista bibliotek środowiska uruchomieniowego do łączenia ze środowiskiem uruchomieniowym AddressSanitizer w programie Visual Studio 17.7 (wersja zapoznawcza 3). Aby uzyskać więcej informacji na temat /MT opcji (statycznie łączyć środowisko uruchomieniowe) i /MD (dynamicznie łączyć redist w czasie wykonywania), zobacz /MD, /MT, /LD (Użyj biblioteki czasu wykonywania).

Uwaga

W poniższej tabeli {arch} znajduje się wartość i386 lub x86_64. Te biblioteki używają konwencji języka Clang dla nazw architektury. Konwencje MSVC są zwykle x86 , a x64 nie i386 i x86_64, ale odnoszą się do tych samych architektur.

Opcja CRT Biblioteka środowiska uruchomieniowego AddressSanitizer (.lib) Plik binarny środowiska uruchomieniowego adresu (.dll)
/MT lub /MTd clang_rt.asan_dynamic-{arch}, clang_rt.asan_static_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MD lub /MDd clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}

Na poniższym diagramie przedstawiono sposób, w jaki biblioteki środowiska uruchomieniowego języka są połączone z /MTopcjami kompilatora , , /MTd, /MDi /MDd :

Diagram przedstawiający sposób, w jaki biblioteki uruchomieniowe są połączone dla różnych opcji kompilatora.

Obraz przedstawia trzy scenariusze łączenia biblioteki środowiska uruchomieniowego. Pierwszy to /MT lub /MTd. My_exe.exe i my_dll.dll są wyświetlane z własnymi kopiami statycznie połączonych środowisk VCRuntime, Universal CRT i C++. Scenariusze pokazują /MD, w których zarówno my_exe.exe, jak i my_dll.dll współużytkuje vcruntime140.dll, ucrtbase.dll i msvcp140.dll. W ostatnim scenariuszu pokazano /MDd, w którym zarówno my_exe.exe, jak i my_dll.dll współużytkować wersje debugowania środowisk uruchomieniowych: vcruntime140d.dll, ucrtbased.dll i msvcp140d.dll

Na poniższym diagramie przedstawiono sposób, w jaki biblioteka ASan jest połączona z różnymi opcjami kompilatora:

Diagram przedstawiający sposób, w jaki biblioteka DLL środowiska uruchomieniowego ASan jest połączona.

Obraz przedstawia cztery scenariusze łączenia biblioteki środowiska uruchomieniowego ASan. Scenariusze dotyczą /MT (statycznie połączyć środowisko uruchomieniowe), /MTd (statycznie połączyć środowisko uruchomieniowe debugowania), /MD (dynamicznie połączyć redystrybucj w czasie wykonywania), /MDd (dynamicznie połączyć redystrybut debugowania w czasie wykonywania). We wszystkich przypadkach my_exe.exe linki i jego skojarzenia my_dll.dll link do pojedynczego wystąpienia clang-rt.asan-dynamix-x86_64.dll.

Nawet w przypadku statycznego łączenia biblioteka DLL środowiska uruchomieniowego ASan musi być obecna w czasie wykonywania — w przeciwieństwie do innych składników środowiska uruchomieniowego języka C.

Poprzednie wersje

Przed programem Visual Studio 17.7 (wersja zapoznawcza 3) kompilacje statycznie połączone (/MT lub /MTd) nie używały zależności biblioteki DLL. Zamiast tego środowisko uruchomieniowe AddressSanitizer zostało statycznie połączone z plikiem EXE użytkownika. Następnie projekty DLL ładują eksporty z pliku EXE użytkownika w celu uzyskania dostępu do funkcji ASan.

Dynamicznie połączone projekty (/MD lub /MDd) używały różnych bibliotek i bibliotek DLL w zależności od tego, czy projekt został skonfigurowany do debugowania, czy wydania. Aby uzyskać więcej informacji na temat tych zmian i ich motywacji, zobacz MSVC Address Sanitizer — jedna biblioteka DLL dla wszystkich konfiguracji środowiska uruchomieniowego.

W poniższej tabeli opisano poprzednie zachowanie linku biblioteki środowiska uruchomieniowego AddressSanitizer przed programem Visual Studio 17.7 (wersja zapoznawcza 3):

Opcja CRT BIBLIOTEKA DLL lub EXE DEBUGOWANIA? Biblioteka ASan (.lib) Dane binarne środowiska uruchomieniowego ASan (.dll)
/MT EXE Nie. clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch} Brak
/MT DLL Nie. clang_rt.asan_dll_thunk-{arch} Brak
/MD Lub Nie. clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MT EXE Tak clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch} Brak
/MT DLL Tak clang_rt.asan_dbg_dll_thunk-{arch} None
/MD Dowolny Tak clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch} clang_rt.asan_dbg_dynamic-{arch}

Na poniższym diagramie pokazano, jak biblioteka ASan była połączona z różnymi opcjami kompilatora przed programem Visual Studio 2022 17.7 (wersja zapoznawcza 3):

Diagram przedstawiający sposób, w jaki biblioteka DLL środowiska uruchomieniowego ASan została połączona przed programem Visual Studio 2022 (wersja zapoznawcza 3).

Obraz przedstawia cztery scenariusze łączenia biblioteki środowiska uruchomieniowego ASan. Scenariusze dotyczą /MT (statycznie połączyć środowisko uruchomieniowe), /MTd (statycznie połączyć środowisko uruchomieniowe debugowania), /MD (dynamicznie połączyć redystrybucj w czasie wykonywania), /MDd (dynamicznie połączyć redystrybut debugowania w czasie wykonywania). W przypadku /MT my_exe.exe ma statycznie połączoną kopię środowiska uruchomieniowego ASan. my_dll.dll linki do środowiska uruchomieniowego ASan w my_exe.exe. W przypadku /MTd diagram jest taki sam, z wyjątkiem tego, że używa statycznie połączonego środowiska uruchomieniowego ASan debugowania. W przypadku /MD zarówno my_exe.exe, jak i my_dll.dll łącze do dynamicznie połączonego środowiska uruchomieniowego ASan o nazwie clang_rt.asan_dynamic-x86_64.dll. W przypadku /MDd diagram jest taki sam, z wyjątkiem my_exe.exe i my_dll.dll link do środowiska uruchomieniowego debugowania ASan o nazwie clang_rt.asan_dbg_dynamic-x86_64.dll.

Przechwytywanie funkcji

Funkcja AddressSanitizer umożliwia przechwytywanie funkcji za pomocą wielu technik na gorąco. Te techniki są najlepiej udokumentowane w samym kodzie źródłowym.

Biblioteki środowiska uruchomieniowego przechwytują wiele typowych funkcji zarządzania pamięcią i manipulowania pamięcią. Aby zapoznać się z listą, zobacz AddressSanitizer list of intercepted functions (Lista przechwyconych funkcji). Przechwytniki alokacji zarządzają metadanymi i bajtami w tle powiązanymi z każdym wywołaniem alokacji. Za każdym razem, gdy funkcja CRT, taka jak malloc lub delete jest wywoływana, przechwytatory ustawiają określone wartości w regionie Pamięci w tle AddressSanitizer, aby wskazać, czy te lokalizacje sterty są obecnie dostępne i jakie są granice alokacji. Te bajty w tle umożliwiają kompilatorowi sprawdzanie bajtów w tle w celu określenia, czy obciążenie lub magazyn jest prawidłowe.

Przechwytywanie nie ma gwarancji powodzenia. Jeśli prolog funkcji jest za krótki do jmp zapisania, przechwytywanie może zakończyć się niepowodzeniem. Jeśli wystąpi błąd przechwytywania, program zgłasza błąd debugbreak i zatrzymuje. Jeśli dołączysz debuger, przyczyną problemu przechwytywania jest jasne. Jeśli masz ten problem, zgłoś usterkę.

Uwaga

Użytkownicy mogą opcjonalnie próbować kontynuować przecięcie nieudanego przechwycenia, ustawiając zmienną środowiskową ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE na dowolną wartość. Kontynuowanie niepowodzenia przechwytywania może spowodować pominięcie raportów o błędach dla tej funkcji.

Niestandardowe alokatory i środowisko uruchomieniowe AddressSanitizer

Środowisko uruchomieniowe AddressSanitizer udostępnia przechwytniki dla typowych interfejsów alokatora, malloc/free, newdelete/,/HeapFreeHeapAlloc(za pośrednictwem metody ).RtlAllocateHeap/RtlFreeHeap Wiele programów korzysta z niestandardowych alokatorów z jednego lub innego powodu, przykładem może być dowolny program korzystający z interfejsu lub rozwiązania przy użyciu dlmalloc interfejsu std::allocator i VirtualAlloc(). Kompilator nie może automatycznie dodawać wywołań zarządzania pamięcią w tle do niestandardowego alokatora. Użytkownik ponosi odpowiedzialność za korzystanie z dostarczonego interfejsu zatruwania ręcznego. Ten interfejs API umożliwia tym alokatorom prawidłowe działanie z istniejącym środowiskiem uruchomieniowym AddressSanitizer i konwencjami bajtów w tle.

Interfejs zatruwania narzędzia AddressSanitizer ręcznego

Interfejs do obsługi jest prosty, ale nakłada ograniczenia wyrównania na użytkownika. Użytkownicy mogą importować te prototypy, importując sanitizer/asan_interface.hplik . Oto prototypy funkcji interfejsu:

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

Dla wygody plik nagłówka interfejsu AddressSanitizer udostępnia makra otoki. Te makra sprawdzają, czy funkcja AddressSanitizer jest włączona podczas kompilacji. Umożliwiają one kodowi źródłowemu pominięcie wywołań funkcji zatrucia, gdy nie są potrzebne. Te makra powinny być preferowane w przypadku bezpośredniego wywoływania powyższych funkcji:

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

Wymagania dotyczące wyrównania dla zatrucia narzędzia AddressSanitizer

Każde ręczne zatrucie bajtów w tle musi uwzględniać wymagania dotyczące wyrównania. W razie potrzeby użytkownik musi dodać dopełnienie, aby bajty w tle zakończyły się granicą bajtów w pamięci w tle. Każdy bit w pamięci w tle AddressSanitizer koduje stan pojedynczego bajtu w pamięci aplikacji. To kodowanie oznacza całkowity rozmiar każdej alokacji, w tym wszelkie wypełnienie, musi być wyrównany do granicy 8-bajtowej. Jeśli wymaganie wyrównania nie jest spełnione, może to prowadzić do nieprawidłowego raportowania błędów. Niepoprawne raportowanie może manifestować się jako brakujące raporty (fałszywie ujemne) lub raporty dotyczące błędów (fałszywie dodatnie).

Aby zapoznać się z ilustracją wymagań dotyczących wyrównania i potencjalnych problemów, zobacz podane przykłady wyrównania rozwiązania ASan. Jednym z nich jest mały program, który pokazuje, co może pójść nie tak z ręcznym zatruciem pamięci w tle. Druga to przykładowa implementacja ręcznego zatrucia za pomocą interfejsu std::allocator .

Opcje czasu wykonywania

Program Microsoft C/C++ (MSVC) używa środowiska uruchomieniowego opartego na środowisku uruchomieniowym Clang AddressSanitizer z repozytorium llvm-project. W związku z tym większość opcji środowiska uruchomieniowego jest współdzielona między dwiema wersjami. Pełna lista publicznych opcji środowiska uruchomieniowego Clang jest dostępna tutaj. Dokumentujemy pewne różnice w poniższych sekcjach. Jeśli odkryjesz opcje, które nie działają zgodnie z oczekiwaniami, zgłoś usterkę.

Nieobsługiwane opcje AddressSanitizer

  • detect_container_overflow
  • unmap_shadow_on_exit

Uwaga

Opcja halt_on_error środowiska uruchomieniowego AddressSanitizer nie działa w oczekiwany sposób. W bibliotekach środowiska uruchomieniowego Clang i MSVC wiele typów błędów jest uznawanych za nieobsługiwalne, w tym większość błędów uszkodzenia pamięci.

Aby uzyskać więcej informacji, zobacz sekcję Różnice w języku Clang 12.0 .

Opcje środowiska uruchomieniowego narzędzia AddressSanitizer specyficzne dla MSVC

  • windows_hook_legacy_allocators Wartość logiczna, ustawiona na wartość , aby false wyłączyć przechwytywanie GlobalAlloc obiektów i LocalAlloc alokatorów.

    Uwaga

    Opcja windows_hook_legacy_allocators nie była dostępna w publicznym środowisku uruchomieniowym llvm-project podczas pisania tego artykułu. Opcja może zostać ostatecznie wpłatwana z powrotem do projektu publicznego; jednak zależy to od przeglądu kodu i akceptacji społeczności.

    Opcja windows_hook_rtl_allocators, wcześniej włączona funkcja , podczas gdy funkcja AddressSanitizer była eksperymentalna, jest teraz domyślnie włączona. W wersjach wcześniejszych niż program Visual Studio 2022 w wersji 17.4.6 domyślną wartością opcji jest false. W programie Visual Studio 2022 w wersji 17.4.6 lub nowszej opcja windows_hook_rtl_allocators jest domyślnie ustawiona na true.

  • iat_overwrite Ciąg, domyślnie ustawiony na "error" wartość . Inne możliwe wartości to "protect" i "ignore". Niektóre moduły mogą zastąpić import address table inne moduły w celu dostosowania implementacji niektórych funkcji. Na przykład sterowniki często udostępniają niestandardowe implementacje dla określonego sprzętu. Opcja iat_overwrite zarządza ochroną środowiska uruchomieniowego AddressSanitizer przed zastąpieniem określonych memoryapi.h funkcji. Środowisko uruchomieniowe śledzi obecnie VirtualAllocfunkcje , VirtualProtecti VirtualQuery na potrzeby ochrony. Ta opcja jest dostępna w programie Visual Studio 2022 w wersji 17.5 (wersja zapoznawcza 1) i nowszych wersjach. Następujące iat_overwrite wartości określają, jak środowisko uruchomieniowe reaguje, gdy funkcje chronione są zastępowane:

    • Jeśli jest ustawiona wartość "error" (wartość domyślna), środowisko uruchomieniowe zgłasza błąd za każdym razem, gdy zostanie wykryte zastąpienie.
    • Jeśli jest ustawiona wartość "protect", środowisko uruchomieniowe próbuje uniknąć używania zastąpionej definicji i przechodzi dalej. W rzeczywistości oryginalna memoryapi definicja funkcji jest używana z wewnątrz środowiska uruchomieniowego, aby uniknąć nieskończonej rekursji. Inne moduły w procesie nadal używają nadpisanej definicji.
    • Jeśli jest ustawiona wartość "ignore", środowisko uruchomieniowe nie próbuje poprawić żadnych zastąpionych funkcji i kontynuuje wykonywanie.
  • windows_fast_fail_on_error Wartość logiczna (wartość domyślna false) jest ustawiona na wartość , aby true umożliwić zakończenie procesu z __fastfail(71) po wydrukowaniu raportu o błędach.

Uwaga

Gdy abort_on_error wartość jest ustawiona na true, w systemie Windows program kończy działanie z exit(3). Aby nie zmienić bieżącego zachowania, postanowiliśmy wprowadzić tę nową opcję. Jeśli zarówno abort_on_error, jak i windows_fast_fail_on_error są prawdziwe, program zakończy działanie z __fastfail.

AddressSanitizer lista przechwyconych funkcji (Windows)

Środowisko uruchomieniowe AddressSanitizer sprawdza wiele funkcji w celu włączenia kontroli bezpieczeństwa pamięci w czasie wykonywania. Oto niewyczerpująca lista funkcji monitorujących środowisko uruchomieniowe AddressSanitizer.

Domyślne przechwytniki

Opcjonalne przechwytniki

Przechwytniki wymienione w tym miejscu są instalowane tylko wtedy, gdy jest włączona opcja środowiska uruchomieniowego AddressSanitizer. Ustaw windows_hook_legacy_allocators wartość na , aby false wyłączyć przechwytywanie starszej wersji alokatora. set ASAN_OPTIONS=windows_hook_legacy_allocators=false

Zobacz też

AddressSanitizer — omówienie
Rozwiązywanie znanych problemów z programemSanitizer
Dokumentacja języka i kompilacji narzędzia AddressSanitizer
Bajty w tle addressSanitizer
AddressSanitizer — chmura lub testowanie rozproszone
Integracja debugera AddressSanitizer
Przykłady błędów addressSanitizer