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 работает на этапе компиляции и во время выполнения программы. Он состоит из двух компонентов:
- Инструментирующий модуль (компилятор): на этапе компиляции в код программы вставляются дополнительные проверки (инструментирование). Для каждой операции чтения или записи памяти (например, присваивание значения переменной, вызов функции
memcpy) генерируется код, проверяющий, находится ли адрес в допустимой области.
- Библиотека времени выполнения (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 →