AddressSanitizer

Обзор

Языки C и C++ являются мощными, но могут страдать от класса ошибок, влияющих на правильность программы и безопасность программы. Начиная с Visual Studio 2019 версии 16.9 компилятор Microsoft C/C++ (MSVC) и интегрированная среда разработки поддерживает санитизатор AddressSanitizer . AddressSanitizer (ASan) — это технология компилятора и среды выполнения, которая обнаруживает множество трудно обнаруживаемых ошибок без ложных срабатываний:

Используйте AddressSanitizer, чтобы сократить время, затраченное на:

  • Базовая правильность
  • Переносимость кроссплатформенных платформ
  • Безопасность
  • Стресс-тестирование
  • Интеграция нового кода

AddressSanitizer, первоначально представленный Google, предоставляет технологии обнаружения ошибок во время выполнения, которые используют существующие системы сборки и существующие тестовые ресурсы напрямую.

AddressSanitizer интегрирован с системой проектов Visual Studio, системой сборки CMake и интегрированной среды разработки. Проекты могут включить AddressSanitizer, задав свойство проекта или используя один дополнительный параметр компилятора: /fsanitize=address Новый параметр совместим со всеми уровнями оптимизации и конфигурации x86 и x64. Однако он не совместим с изменением и продолжением, добавочным связыванием и /RTC.

Начиная с Visual Studio 2019 версии 16.9 технология AddressSanitizer Майкрософт обеспечивает интеграцию с интегрированной средой разработки Visual Studio. Функционал может по желанию создавать файл аварийного дампа при обнаружении ошибки во время выполнения. Если вы устанавливаете переменную среды перед запуском ASAN_SAVE_DUMPS=MyFileName.dmp программы, файл аварийного дампа создается с дополнительными метаданными для эффективной отладки точно диагностированных ошибок. Эти файлы дампа облегчают расширенное использование AddressSanitizer для:

  • Тестирование локального компьютера
  • Локальное распределенное тестирование
  • Облачные рабочие процессы для тестирования

Установка AddressSanitizer

Процессы C++ в установщике Visual Studio по умолчанию устанавливают библиотеки AddressSanitizer и интеграцию с интегрированной средой разработки. Однако если вы обновляете более раннюю версию Visual Studio 2019, используйте установщик, чтобы включить поддержку ASan после обновления. Установщик можно открыть в главном меню Visual Studio через Средства>Получить средства и компоненты... Выберите Изменить на существующей установке Visual Studio через Visual Studio Installer, чтобы перейти к следующему экрану.

Снимок экрана: установщик Visual Studio. Компонент C++ AddressSanitizer в разделе

Примечание.

Если вы запускаете Visual Studio в новом обновлении, но не установили ASan, при запуске кода появится сообщение об ошибке:

LNK1356: не удается найти библиотеку "clang_rt.asan_dynamic-i386.lib".

Используйте AddressSanitizer

Начните создавать исполняемые файлы с параметром компилятора /fsanitize=address с помощью любого из следующих распространенных методов разработки:

  • Сборки командной строки
  • Система проектов Visual Studio
  • Интеграция Visual Studio CMake

Перекомпилируйте, а затем обычно запустите программу. Генерация этого кода выявляет множество типов точно диагностированных ошибок. Эти ошибки передаются тремя способами: в среде отладки в IDE, через командную строку или в новом типе файла дампа для точной обработки в автономном режиме.

Корпорация Майкрософт рекомендует использовать AddressSanitizer в следующих трех стандартных рабочих процессах:

В этой статье рассматриваются сведения, необходимые для включения трех рабочих процессов, перечисленных ранее. Сведения относятся к реализации AddressSanitizer, зависящей от платформы Windows 10 (и более поздних версий). Эта документация дополняет отличную документацию от Google, Apple и GCC , уже опубликованных.

Примечание.

Поддержка ограничена x86 и x64 в Windows 10 и более поздних версий. Отправьте нам отзыв о том, что вы хотите увидеть в будущих выпусках. Ваши отзывы помогают нам определять приоритеты других санитизаторов в будущем, таких как /fsanitize=thread, , /fsanitize=leak/fsanitize=memoryили /fsanitize=undefined/fsanitize=hwaddress. При возникновении проблем можно сообщить об ошибках .

Использование AddressSanitizer из командной строки разработчика

/fsanitize=address Используйте параметр компилятора в командной строкеразработчика, чтобы включить компиляцию для среды выполнения AddressSanitizer. Параметр /fsanitize=address совместим с существующими уровнями оптимизации C++ или C (например, /Od, /O1, /O2и /O2 /GL). Опция работает со статическими и динамическими CRT (например, /MD, /MDd, /MT, и /MTd). Он работает независимо от того, создаете ли файл EXE или библиотеку DLL. Сведения об отладке необходимы для оптимального форматирования стеков вызовов. В следующем примере cl /fsanitize=address /Zi передается в командной строке.

Примечание.

AddressSanitizer не поддерживает оптимизацию на основе профилей (PGO). AddressSanitizer не следует использовать в рабочей среде.

Библиотеки AddressSanitizer (.lib файлы) подключаются для вас автоматически. Дополнительные сведения см. в справочнике по AddressSanitizer: языку, сборке и отладке.

Пример: глобальное базовое переполнение буфера

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

Используя командную строку разработчика для Visual Studio 2019, скомпилируйте main.cpp с помощью /fsanitize=address /Zi

Снимок экрана: командная строка с командой для компиляции с параметрами AddressSanitizer. Команда : cl main.cpp -faanitize-address /Zi.

При запуске результирующего main.exe в командной строке создается отформатированный отчет об ошибке, который следует.

Рассмотрим наложенные красные коробки, которые выделяют семь ключевых элементов информации:

Снимок экрана отладчика, показывающий основную ошибку переполнения глобальной памяти.

В отчете об ошибке есть семь красных выделений, определяющих ключевые фрагменты информации. Они связаны с нумерованным списком, который следует на этом снимке экрана. Нумерованные поля выделяют следующий текст: 1) global-buffer-overflow 2) WRITE размером 4 3) basic-global-overflow.cpp 7 4) справа от глобальной переменной x, определенной в области условных обозначений basic-global-overflow.cpp:3:8) размером 400 6) 00 00[f9]f9 f9 7) Box находится в области условных обозначений тени байтов и содержит глобальную красную зону: f9

Красные выделения, от верхнего до нижнего

  1. Ошибка безопасности памяти — это переполнение глобального буфера.
  2. Существовало 4 байта (32 бита), хранящихся вне любой определяемой пользователем переменной.
  3. Операция записи произошла в функции main(), определенной в файле basic-global-overflow.cpp на 7 строке.
  4. Переменная с именем x определяется в basic-global-overflow.cpp в строке 3, начиная с столбца 8
  5. Эта глобальная переменная x имеет размер 400 байт
  6. Точный теневой байт, описывающий адрес, ориентированный на магазин, имел значение 0xf9
  7. Согласно легенде о теневых байтах, 0xf9 является областью заполнения справа от int x[100].

Примечание.

Имена функций в стеке вызовов создаются с помощью символа LLVM, вызываемого средой выполнения при ошибке.

Использование AddressSanitizer в Visual Studio

AddressSanitizer интегрирован в среду разработки Visual Studio. Чтобы включить AddressSanitizer для проекта MSBuild, щелкните проект правой кнопкой мыши в Обозреватель решений и выберите "Свойства". В диалоговом окне "Страницы свойств" выберите Свойства конфигурации>C/C++>Общие сведения, а затем измените параметр Enable AddressSanitizer. Нажмите ОК, чтобы сохранить внесенные изменения.

Снимок экрана: диалоговое окно

Чтобы выполнить сборку из интегрированной среды разработки, отказаться от любых несовместимых параметров. Для существующего проекта, скомпилированного с помощью /Od (или режима отладки), может потребоваться отключить следующие параметры:

Чтобы создать и запустить отладчик, нажмите клавишу F5. В Visual Studio появляется окно "Исключение выброшено"

Снимок экрана отладчика, показывающий ошибку переполнения глобального буфера.

Использование AddressSanitizer с использованием Visual Studio: CMake

Чтобы включить AddressSanitizer для проекта CMake, созданного для целевой платформы Windows, выполните следующие действия:

  1. Откройте раскрывающийся список "Конфигурации" на панели инструментов в верхней части интегрированной среды разработки и выберите пункт "Управление конфигурациями".

    Снимок экрана, раскрывающийся список конфигурации CMake. В нем отображаются такие параметры, как x64 Debug, x64 Release и т. д. В нижней части списка выделена опция

    Откроется редактор параметров проекта CMake, который отражает содержимое файла проекта CMakeSettings.json .

  2. Выберите ссылку "Изменить JSON " в редакторе. Этот выбор переключает представление на необработанный JSON.

  3. Добавьте следующий фрагмент кода в "windows-base" предустановку, внутри "configurePresets": чтобы включить AddressSanitizer.

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

    "configurePresets" выглядит примерно так, после этого:

        "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. AddressSanitizer не работает, если указан параметр edit-and-continue (/ZI), который включен по умолчанию для новых проектов CMake. В CMakeLists.txt, оставьте комментарий (добавьте префикс #) к строке, начинающейся с set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT". Эта строка выглядит примерно так, после этого:

    # 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. Введите CTRL+S , чтобы сохранить этот JSON-файл

  6. Очистите каталог кэша CMake и выполните перенастройку, выбрав в меню Visual Studio: Проект>Удалить кэш и Перенастроить. Нажмите кнопку "Да", когда появится запрос, чтобы очистить каталог кэша и перенастроить его.

  7. Замените содержимое исходного файла (например, CMakeProject1.cppна следующее:

    // 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. Выберите F5 для повторной компиляции и запуска под отладчиком.

    Скриншот демонстрирует ошибку при сборке с использованием CMake.

    Снимок экрана исключения, в котором говорится: Ошибка Address Sanitizer: переполнение глобального буфера. В фоновом режиме данные от Address Sanitizer отображаются в командном окне.

Аварийные дампы AddressSanitizer

Мы представили новые функции в AddressSanitizer для использования с облачными и распределенными рабочими процессами. Эта функция позволяет в автономном режиме просматривать ошибку AddressSanitizer в интегрированной среде разработки. Ошибка отображается поверх вашего исходного кода, так же как и в интерактивном сеансе отладки.

Эти новые файлы дампа могут привести к эффективности при анализе ошибки. Вам не нужно повторно запускать или находить удаленные данные или искать компьютер, который был отключен.

Чтобы создать новый тип файла дампа, который можно просмотреть в Visual Studio на другом компьютере позже:

set ASAN_SAVE_DUMPS=MyFileName.dmp

Начиная с Visual Studio 16.9, вы можете отобразить точно диагностированную ошибку, хранящуюся в *.dmp файле, в верхней части исходного кода.

Эта новая функция аварийного дампа обеспечивает облачные рабочие процессы или распределенное тестирование. Его также можно использовать для регистрации подробной ошибки, подлежащей исправлению, в любой ситуации.

Примеры ошибок

AddressSanitizer может обнаружить несколько типов ошибок неправильного использования памяти. Ниже приведено множество ошибок среды выполнения при запуске двоичных файлов, скомпилированных с помощью параметра компилятора AddressSanitizer (/fsanitize=address).

Дополнительные сведения о примерах см. в разделе Примеры ошибок AddressSanitizer.

Различия с Clang 12.0

В настоящее время MSVC отличается от Clang 12.0 в двух функциональных областях:

  • stack-use-after-scope — этот параметр включен по умолчанию и не может быть отключен.
  • стек-use-after-return — эта функция требует дополнительного параметра компилятора и не доступна только параметром ASAN_OPTIONS.

Эти решения были приняты для уменьшения матрицы тестов, необходимой для доставки этой первой версии.

Функции, которые могут привести к ложным срабатываниям в Visual Studio 2019 16.9, не были включены. Эта дисциплина обеспечивает поддержание целостности тестирования, необходимой при рассмотрении совместимости с десятилетиями существующего кода. Дополнительные возможности можно рассмотреть в последующих выпусках:

Дополнительные сведения см. в разделе "Создание для AddressSanitizer" с помощью MSVC.

Существующая документация отрасли

Обширная документация уже существует для этих языковых и зависимых от платформ реализаций технологии AddressSanitizer.

В этой основополагающей статье о AddressSanitizer (external) описывается реализация.

См. также

Известные проблемы AddressSanitizer
Справочник по сборке и языку AddressSanitizer
Справочник по среде выполнения AddressSanitizer
Теневые байты AddressSanitizer
Облачное или распределенное тестирование AddressSanitizer
Интеграция отладчика AddressSanitizer
Примеры ошибок AddressSanitizer