Открыть сервис

AddressSanitizer

AddressSanitizer (сокращённо ASan) — это инструмент динамического анализа программного кода, предназначенный для обнаружения ошибок работы с памятью, таких как переполнение буфера, использование памяти после освобождения (use-after-free), двойное освобождение (double-free) и утечки памяти. Разработан компанией Google и входит в состав компиляторов GCC (начиная с версии 4.8) и Clang (начиная с версии 3.1). AddressSanitizer используется для тестирования и отладки программ на языках C и C++, а также, в ограниченном виде, на других языках, компилируемых в машинный код.

История

Разработка AddressSanitizer началась в 2011 году в рамках проекта Google по улучшению безопасности и надёжности программного обеспечения. Первая версия была представлена в 2012 году, а в 2013 году инструмент был включён в состав свободного набора компиляторов LLVM/Clang. В 2014 году поддержка AddressSanitizer была добавлена в GCC (GNU Compiler Collection). Основными авторами инструмента являются Константин Серебряный и Дмитрий Вьюков (оба — сотрудники Google). Название «Sanitizer» (от англ. sanitize — «очищать») отражает цель инструмента: выявлять и «очищать» код от ошибок памяти.

Принцип работы

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

  1. Инструментирующий модуль (компилятор): на этапе компиляции в код программы вставляются дополнительные проверки (инструментирование). Для каждой операции чтения или записи памяти (например, присваивание значения переменной, вызов функции memcpy) генерируется код, проверяющий, находится ли адрес в допустимой области.
  1. Библиотека времени выполнения (runtime): во время выполнения программы создаётся специальная область памяти — «теневая память» (shadow memory). Каждые 8 байт основной памяти программы отображаются на 1 байт теневой памяти, который хранит состояние: доступен ли блок для чтения/записи, освобождён ли он, или находится в «красной зоне» (redzone).

Теневая память и красные зоны

AddressSanitizer выделяет память с избытком: вокруг каждого выделенного блока (например, результата вызова malloc) создаются «красные зоны» — небольшие участки памяти, помеченные в теневой памяти как недоступные. Любая попытка записи или чтения в красной зоне приводит к немедленному срабатыванию инструмента и выводу сообщения об ошибке. Размер красной зоны обычно составляет 32 байта, но может варьироваться в зависимости от настроек.

Обнаружение use-after-free

При освобождении памяти (вызов free) AddressSanitizer не возвращает её операционной системе, а помещает в специальный список «карантина» (quarantine). Память остаётся недоступной для записи, но её адрес продолжает отслеживаться. Если программа пытается обратиться к этой памяти после освобождения, инструмент фиксирует ошибку use-after-free. Размер карантина настраивается (по умолчанию — 256 МБ).

Виды обнаруживаемых ошибок

AddressSanitizer способен выявлять следующие типы ошибок:

  • Переполнение буфера (buffer overflow): запись или чтение за границами выделенного массива или структуры.
  • Использование памяти после освобождения (use-after-free): обращение к участку памяти, который был ранее освобождён.
  • Двойное освобождение (double-free): повторный вызов free для одного и того же указателя.
  • Утечки памяти (memory leaks): память, выделенная с помощью malloc/new, не освобождённая до завершения программы (обнаруживается с помощью дополнительного модуля LeakSanitizer).
  • Переполнение стека (stack buffer overflow): выход за границы локальных массивов, размещённых на стеке.
  • Использование неинициализированной памяти (в ограниченном виде, с помощью MemorySanitizer).

Применение

AddressSanitizer широко используется в разработке и тестировании программного обеспечения, особенно в проектах, где критична безопасность и надёжность:

  • Тестирование и отладка: инструмент запускается во время выполнения тестов (unit-тесты, интеграционные тесты). Если тест вызывает ошибку памяти, ASan выдаёт подробный отчёт с указанием файла, строки кода и типа ошибки.
  • Fuzzing (фаззинг): AddressSanitizer часто комбинируется с фаззерами (например, AFL, libFuzzer) для автоматического поиска уязвимостей. Фаззер генерирует случайные входные данные, а ASan отслеживает, не приводят ли они к ошибкам памяти.
  • Разработка ядер операционных систем: существуют версии AddressSanitizer для ядра Linux (KASan — Kernel AddressSanitizer), которые позволяют обнаруживать ошибки памяти в драйверах и модулях ядра.
  • Встраиваемые системы: инструмент используется при разработке прошивок и встроенного ПО, где ошибки памяти могут привести к критическим сбоям.

Ограничения и недостатки

  • Производительность: инструментирование кода приводит к замедлению выполнения программы в среднем в 2–3 раза (по данным разработчиков, до 73% slowdown). Потребление памяти увеличивается в 2–3 раза за счёт теневой памяти и красных зон.
  • Не все ошибки обнаруживаются: AddressSanitizer не выявляет ошибки, связанные с чтением неинициализированной памяти (для этого используется MemorySanitizer) или с гонками данных в многопоточных программах (ThreadSanitizer).
  • Ложные срабатывания: в редких случаях, особенно при использовании нестандартных аллокаторов или низкоуровневых операций с памятью, возможны ложные положительные результаты.
  • Несовместимость с некоторыми оптимизациями: некоторые оптимизации компилятора (например, встраивание функций) могут снижать точность отчётов.

Альтернативы

  • Valgrind (Memcheck): более медленный, но не требующий перекомпиляции инструмент для обнаружения ошибок памяти. Замедление выполнения может достигать 10–20 раз.
  • Electric Fence: библиотека для обнаружения переполнений буфера, работающая на уровне страниц памяти.
  • MemorySanitizer (MSan): инструмент для обнаружения чтения неинициализированной памяти, также входящий в состав Sanitizer-семейства Google.
  • ThreadSanitizer (TSan): для обнаружения гонок данных в многопоточных программах.
  • LeakSanitizer (LSan): модуль для обнаружения утечек памяти, часто используется совместно с AddressSanitizer.

Интересные факты

  • AddressSanitizer был использован для обнаружения сотен ошибок в таких крупных проектах, как ядро Linux, браузер Chromium, база данных MySQL и интерпретатор Python.
  • В 2012 году инструмент помог найти более 300 ошибок в коде проекта Chromium за несколько месяцев тестирования.
  • AddressSanitizer поддерживает не только C и C++, но и другие языки, компилируемые в машинный код, например Rust (через инструментирование LLVM) и Objective-C.
  • В 2015 году за разработку AddressSanitizer Константин Серебряный и Дмитрий Вьюков получили награду ACM SIGSOFT Distinguished Paper Award.

Источники

  • Serebryany, K., Bruening, D., Potapenko, A., & Vyukov, D. (2012). AddressSanitizer: A Fast Address Sanity Checker. Proceedings of the 2012 USENIX Annual Technical Conference.
  • Документация LLVM: AddressSanitizer.
  • Документация GCC: Instrumentation Options.
  • Официальный репозиторий AddressSanitizer на GitHub.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →