AddressSanitizer

Omówienie

Języki C i C++ są zaawansowane, ale mogą cierpieć na klasę usterek, które wpływają na poprawność programu i zabezpieczenia programu. Począwszy od Visual Studio 2019 w wersji 16.9, kompilator Microsoft C/C++ (MSVC) i środowisko IDE obsługują AddressSanitizer sanitizer. AddressSanitizer (ASan) to technologia kompilatora i środowiska uruchomieniowego, która uwidacznia wiele trudnych do znalezienia błędów z zerowymi wynikami fałszywie dodatnimi:

Dlaczego warto używać narzędzia AddressSanitizer

Użyj narzędzia AddressSanitizer, aby skrócić czas spędzony na:

  • Podstawowa poprawność
  • Przenośność międzyplatformowa
  • Zabezpieczenia
  • Testy obciążeniowe
  • Integrowanie nowego kodu

AddressSanitizer, pierwotnie wprowadzony przez firmę Google, udostępnia technologie znajdowania błędów środowiska uruchomieniowego, które używają istniejących systemów kompilacji i istniejących zasobów testowych bezpośrednio.

Tworzenie integracji i zgodności

AddressSanitizer jest zintegrowany z systemem projektu Visual Studio, systemem kompilacji CMake i środowiskiem IDE. Projekty mogą włączać metodę AddressSanitizer, ustawiając właściwość projektu lub używając jednej dodatkowej opcji kompilatora: /fsanitize=address. Ta opcja jest zgodna ze wszystkimi poziomami optymalizacji i konfiguracji x86 i x64. Nie jest jednak zgodny z funkcją edytowania i kontynuowania, łączenia przyrostowego i /RTC.

Obsługa zrzutów pamięci

Począwszy od programu Visual Studio 2019 w wersji 16.9 technologia AddressSanitizer firmy Microsoft umożliwia integrację ze środowiskiem IDE programu Visual Studio. Funkcjonalność może opcjonalnie utworzyć zrzut awaryjny, gdy sanitizer znajdzie błąd w trakcie działania. Jeśli ustawisz zmienną ASAN_SAVE_DUMPS=MyFileName.dmp środowiskową przed uruchomieniem programu, zostanie utworzony plik zrzutu awaryjnego z dodatkowymi metadanymi na potrzeby wydajnego debugowania pośmiertnego precyzyjnego diagnozowania usterek. Te pliki zrzutu ułatwiają rozszerzone korzystanie z narzędzia AddressSanitizer:

  • Testowanie maszyn lokalnych
  • Lokalne testowanie rozproszone
  • Przepływy pracy oparte na chmurze na potrzeby testowania

Instalowanie narzędzia AddressSanitizer

Zestawy robocze C++ w Instalatorze programu Visual Studio domyślnie instalują biblioteki AddressSanitizer i integrację z IDE. Jeśli jednak uaktualniasz starszą wersję programu Visual Studio 2019, użyj Instalatora, aby włączyć obsługę aplikacji ASan po uaktualnieniu. Instalator można otworzyć z menu głównego Visual Studio, wybierając pozycję Tools>Pobierz narzędzia i funkcje. Wybierz Modify w istniejącej instalacji Visual Studio z instalatora Visual Studio, aby przejść do następującego ekranu.

Zrzut ekranu przedstawiający Instalator programu Visual Studio z wyróżnionym składnikiem C++ AddressSanitizer w sekcji „Opcjonalne”.

Uwaga

Jeśli uruchomisz Visual Studio w nowej aktualizacji, ale nie zainstalowano rozwiązania ASan, podczas uruchamiania kodu wystąpi błąd:

LNK1356: nie można odnaleźć biblioteki "clang_rt.asan_dynamic-i386.lib"

Używanie narzędzia AddressSanitizer

Rozpocznij tworzenie plików wykonywalnych przy użyciu opcji kompilatora /fsanitize=address przy użyciu dowolnej z tych typowych metod programowania:

  • Budowanie z linii poleceń
  • System projektu programu Visual Studio
  • Integracja narzędzia CMake programu Visual Studio

Ponownie skompiluj kod, a następnie uruchom program normalnie, aby uwidocznić wiele typów dokładnie zdiagnozowanych usterek. Możesz przejrzeć problemy w środowisku IDE debugera, wierszu polecenia lub pliku zrzutu.

Firma Microsoft zaleca używanie narzędzia AddressSanitizer w tych trzech standardowych przepływach pracy:

W tym artykule opisano informacje wymagane do włączenia trzech wymienionych wcześniej przepływów pracy. Informacje są specyficzne dla implementacji AddressSanitizer zależnej od platformy w systemie Windows 10 (i nowszych). Ta dokumentacja uzupełnia dokumentację firmy Google, Apple i GCC.

Uwaga

Obsługa jest ograniczona do wersji x86 i x64 w systemie Windows 10 lub nowszym. Wyślij nam opinię na temat tego, co chcesz zobaczyć w przyszłych wersjach. Twoja opinia pomaga nam określić priorytety innych środków dezynfekujących na przyszłość, takich jak /fsanitize=thread, /fsanitize=leak, /fsanitize=memory, /fsanitize=undefined lub /fsanitize=hwaddress. Jeśli wystąpią problemy, możesz zgłosić usterki w tym miejscu .

Używanie narzędzia AddressSanitizer z wiersza polecenia dewelopera

Użyj opcji kompilatora /fsanitize=address w wierszu polecenia programisty, aby włączyć kompilowanie dla środowiska uruchomieniowego AddressSanitizer. Opcja /fsanitize=address jest zgodna z istniejącymi poziomami optymalizacji dla języka C++ lub C, na przykład /Od, /O1, /O2 i /O2 /GL. Opcja działa ze statycznymi i dynamicznymi CRT (na przykład /MD, /MDd, /MT, i /MTd). Działa niezależnie od tego, czy tworzysz plik EXE, czy bibliotekę DLL. Informacje debugowania są wymagane do optymalnego formatowania stosów wywołań. W poniższym przykładzie cl /fsanitize=address /Zi jest przekazywany w linii poleceń.

Uwaga

Narzędzie AddressSanitizer nie obsługuje optymalizacji opartej na profilu (PGO). Narzędzie AddressSanitizer nie powinno być używane w środowisku produkcyjnym.

Biblioteki AddressSanitizer (pliki .lib) są automatycznie linkowane. Aby uzyskać więcej informacji, zobacz AddressSanitizer language, build, and debug reference (Informacje o języku AddressSanitizer, kompilacji i debugowaniu).

Przykład — przepełnienie podstawowego buforu globalnego

// basic-global-overflow.cpp
#include <stdio.h>
int x[100];
int main() {
    printf("Hello!\n");
    x[100] = 5; // Boom!
    return 0;
}

Przy użyciu wiersza polecenia dewelopera dla Visual Studio 2019 r. skompiluj basic-global-overflow.cpp używając /fsanitize=address /Zi.

Zrzut ekranu przedstawiający wiersz polecenia z poleceniem

Po uruchomieniu wynikowego basic-global-overflow.exe w wierszu polecenia tworzy sformatowany raport o błędach, który jest pokazany poniżej.

Rozważ nakładane, czerwone pola, które podkreślają siedem kluczowych informacji:

Zrzut ekranu debuggera przedstawiający podstawowy błąd przepełnienia globalnego.

Czerwone podświetlenia, od góry do dołu

  1. Usterka bezpieczeństwa pamięci to globalne przepełnienie bufora.
  2. Było 4 bajty (32 bity) przechowywane poza dowolną zmienną zdefiniowaną przez użytkownika.
  3. Zapis miał miejsce w funkcji main() zdefiniowanej w pliku basic-global-overflow.cpp na linii 7.
  4. Zmienna o nazwie x jest definiowana w basic-global-overflow.cpp w wierszu 3, zaczynając od kolumny 8.
  5. Ta zmienna x globalna ma rozmiar 400 bajtów.
  6. Dokładny bajt cienia opisujący adres docelowy magazynu miał wartość 0xf9.
  7. Legenda bajtów cienia wskazuje, że 0xf9 oznacza obszar wypełnienia po prawej stronie int x[100].

Uwaga

Gdy narzędzie AddressSanitizer zgłasza błąd, środowisko uruchomieniowe ASan wywołuje symbol LLVM w celu utworzenia nazw funkcji w stosie wywołań.

Używanie narzędzia AddressSanitizer w programie Visual Studio

AddressSanitizer jest zintegrowany ze środowiskiem IDE programu Visual Studio. Aby włączyć funkcję AddressSanitizer dla projektu MSBuild, kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań i wybierz Właściwości. W oknie dialogowym Strony Właściwości wybierz Właściwości konfiguracji>C/C++>Ogólne, a następnie zmodyfikuj właściwość Enable AddressSanitizer. Wybierz przycisk OK , aby zapisać zmiany.

Zrzut ekranu przedstawiający okno dialogowe Strony właściwości z właściwością Enable AddressSanitizer.

Aby skompilować z poziomu środowiska IDE, zrezygnuj z wszelkich niezgodnych opcji. W przypadku istniejącego projektu skompilowanego przy użyciu /Od (lub trybu debugowania) może być konieczne wyłączenie następujących opcji:

Aby skompilować i uruchomić debuger, naciśnij F5. W programie Visual Studio pojawi się okno rzucenia wyjątku:

Zrzut ekranu przedstawiający debuger z błędem przepełnienia buforu globalnego.

Użyj narzędzia AddressSanitizer z poziomu programu Visual Studio: CMake

Aby włączyć narzędzie AddressSanitizer dla projektu CMake utworzonego dla systemu Windows, wykonaj następujące kroki:

  1. Otwórz menu rozwijane Konfiguracje na pasku narzędzi w górnej części środowiska IDE i wybierz pozycję Zarządzaj konfiguracjami.

    Zrzut ekranu przedstawiający menu rozwijane konfiguracji CMake, wyświetlające opcje takie jak x64 Debug, x64 Release oraz, na dole listy, „Zarządzaj konfiguracjami...”, jest podświetlone.

    Ta akcja otwiera edytor ustawień projektu CMake, który odzwierciedla zawartość pliku CMakeSettings.json Twojego projektu.

  2. Wybierz link Edytuj kod JSON . To zaznaczenie przełącza widok na nieprzetworzone dane JSON.

  3. Aby włączyć AddressSanitizer, dodaj następujący fragment do ustawienia wstępnego "windows-base", wewnątrz "configurePresets":.

    "environment": {
      "CFLAGS": "/fsanitize=address",
      "CXXFLAGS": "/fsanitize=address"
    }
    

    "configurePresets" wygląda mniej więcej tak: następnie

        "configurePresets": [
          {
            "name": "windows-base",
            "hidden": true,
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "installDir": "${sourceDir}/out/install/${presetName}",
            "cacheVariables": {
              "CMAKE_C_COMPILER": "cl.exe",
              "CMAKE_CXX_COMPILER": "cl.exe"
            },
            "condition": {
              "type": "equals",
              "lhs": "${hostSystemName}",
              "rhs": "Windows"
            },
            "environment": {
              "CFLAGS": "/fsanitize=address",
              "CXXFLAGS": "/fsanitize=address"
            }
          },
    
  4. Narzędzie AddressSanitizer nie działa, jeśli określono opcję edytuj i kontynuuj (/ZI), która jest domyślnie włączona dla nowych projektów CMake. W CMakeLists.txt wykomentuj (poprzedź #) wiersz rozpoczynający się od set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT". Ten wiersz wygląda mniej więcej tak:

    # set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
    
  5. Użyj klawiszy Ctrl+S , aby zapisać ten plik JSON.

  6. Wyczyść katalog pamięci podręcznej CMake i skonfiguruj ponownie, wybierając z menu programu Visual Studio: Project>Usuń pamięć podręczną i ponownie skonfiguruj. Wybierz pozycję Tak , gdy zostanie wyświetlony monit, aby wyczyścić katalog pamięci podręcznej i ponownie skonfigurować.

  7. Zastąp zawartość pliku źródłowego, na przykład CMakeProject1.cpp, następującym kodem:

    // CMakeProject1.cpp : Defines the entry point for the application
    
    #include <stdio.h>
    
    int x[100];
    
    int main()
    {
        printf("Hello!\n");
        x[100] = 5; // Boom!
        return 0;
    }
    
  8. Wybierz F5 , aby ponownie skompilować i uruchomić w debugerze.

    Ten zrzut ekranu przechwytuje błąd z kompilacji narzędzia CMake.

    Zrzut ekranu przedstawiający wyjątek z komunikatem: Błąd AddressSanitizer: przepełnienie globalnego bufora.

Zrzuty pamięci narzędzia AddressSanitizer

AddressSanitizer zawiera funkcje do użycia z chmurowymi i rozproszonymi przepływami pracy. Ta funkcja umożliwia wyświetlanie w trybie offline błędu AddressSanitizer w środowisku IDE. Błąd jest nakładany na źródło, podobnie jak w przypadku sesji debugowania na żywo.

Te pliki zrzutu mogą prowadzić do zwiększenia wydajności podczas analizowania usterki. Nie musisz ponownie uruchamiać, znajdować danych zdalnych ani wyszukiwać maszyny, która przeszła w tryb offline.

Aby utworzyć plik zrzutu, który można wyświetlić w Visual Studio na innej maszynie w późniejszym terminie:

set ASAN_SAVE_DUMPS=MyFileName.dmp

Od wersji Visual Studio 16.9 można wyświetlić precyzyjnie zdiagnozowany błąd, zapisany w pliku *.dmp, bezpośrednio w kodzie źródłowym.

Ta funkcja zrzutu awaryjnego umożliwia przepływy pracy oparte na chmurze lub testowanie rozproszone. Może również służyć do zgłaszania szczegółowej usterki, którą można rozwiązać, w dowolnym scenariuszu.

Przykładowe błędy

AddressSanitizer może wykryć kilka rodzajów błędów nieprawidłowego użycia pamięci. Poniżej przedstawiono wiele błędów środowiska uruchomieniowego zgłaszanych podczas uruchamiania plików binarnych skompilowanych przy użyciu opcji kompilatora AddressSanitizer (/fsanitize=address):

Aby uzyskać więcej informacji na temat przykładów, zobacz AddressSanitizer error examples (Przykłady błędów AddressSanitizer).

Różnice w Clangu 12.0

Program MSVC obecnie różni się od języka Clang 12.0 w dwóch obszarach funkcjonalnych:

  • stack-use-after-scope: to ustawienie jest domyślnie włączone i nie można go wyłączyć.
  • stack-use-after-return: ta funkcjonalność wymaga dodatkowej opcji kompilatora i nie jest dostępna po samym ustawieniu ASAN_OPTIONS.

Podjęto te decyzje w celu zmniejszenia macierzy testowej wymaganej do dostarczenia tej pierwszej wersji.

Funkcje, które mogą prowadzić do wyników fałszywie dodatnich w programie Visual Studio 2019 16.9, nie zostały uwzględnione. Ta dyscyplina wymuszała efektywną integralność testowania niezbędną podczas rozważania współdziałania z dziesięcioleciami istniejącego kodu. Więcej możliwości można rozważyć w kolejnych wersjach:

Aby uzyskać więcej informacji, zobacz Kompilowanie dla AddressSanitizer za pomocą MSVC.

Dokumentacja branżowa

Istnieje obszerna dokumentacja dotycząca tych implementacji języka i platformy technologii AddressSanitizer.

Ten przełomowy artykuł na temat AddressSanitizera (external) opisuje implementację.

Zobacz też