Очиститель кода — это программный инструмент, который обнаруживает ошибки в виде неопределенного или подозрительного поведения компилятора , вставляющего код инструментирования во время выполнения. Класс инструментов был впервые представлен AddressSanitizer (или ASan ) от Google в 2012 году, который использует напрямую отображенную теневую память для обнаружения повреждений памяти, таких как переполнение буфера или доступ к висячему указателю (use-after-free).
ASan от Google, представленный в 2012 году, использует схему теневой памяти для обнаружения ошибок памяти. Он доступен в:
В среднем инструментарий увеличивает время обработки примерно на 73%, а использование памяти на 240%. [5] Существует аппаратно-ускоренный ASan под названием HWAsan, доступный для AArch64 и (в ограниченной степени) x86_64. [6]
AddressSanitizer не обнаруживает никаких неинициализированных чтений памяти (но это обнаруживает MemorySanitizer [7] ), и обнаруживает только некоторые ошибки использования после возврата. [8] Он также не способен обнаружить все произвольные ошибки повреждения памяти, а также все произвольные ошибки записи из-за целочисленных недопереполнений/переполнений (когда целое число с неопределенным поведением используется для вычисления смещений адресов памяти). Смежные буферы в структурах и классах не защищены от переполнения, отчасти для предотвращения нарушения обратной совместимости. [9]
KernelAddressSanitizer ( KASan ) обнаруживает ошибки динамической памяти в ядре Linux. [10] Для инструментирования ядра требуется специальная функция в компиляторе, предоставляющая параметр командной строки, поскольку ядра не используют то же адресное пространство, что и обычные программы. [ 11] [12]-fsanitize=kernel-address
Google также выпустила LeakSanitizer (LSan, утечки памяти ), ThreadSanitizer (TSan, гонки данных и взаимоблокировки ), MemorySanitizer (MSan, неинициализированная память ) и UndefinedBehaviorSanitizer ( UBSan , неопределенное поведение , с детальным контролем). [13] Эти инструменты, как правило, доступны в Clang/LLVM и GCC. [14] [15] [16] Подобно KASan, существуют версии LSan, MSan, TSan, специфичные для ядра, а также полностью оригинальные санитайзеры ядра, такие как KFENCE и KCSan. [17]
Дополнительные инструменты очистки (сгруппированные по компиляторам под флагом -fsanitize или аналогичным) включают: [14] [15] [16]
Дезинфектор кода обнаруживает подозрительное поведение во время работы программы. Один из распространенных способов использования дезинфектора — это его сочетание с фаззингом , который генерирует входные данные, которые с большой вероятностью могут вызвать ошибки. [20]
В этом разделе отсутствует информация о других San; Google ведет подсчет для MSan и TSan. Поиск Sanitizer в Nongnu выдает утечки, найденные LSan в nano, man и т. д. ( март 2023 г. ) |
Разработчики Chromium и Firefox являются активными пользователями AddressSanitizer; [20] [21] инструмент обнаружил сотни ошибок в этих веб-браузерах. [22] Ряд ошибок был обнаружен в FFmpeg [23] и FreeType . [24] Ядро Linux включило AddressSanitizer для архитектуры x86-64 , начиная с версии Linux 4.0.
// Для компиляции: g++ -O -g -fsanitize=address heap-use-after-free.ccint main ( int argc , char ** argv ) { int * массив = новый int [ 100 ]; удалить [] массив ; вернуть массив [ argc ]; // БУМ }
$ ./г.выход==5587==ОШИБКА: AddressSanitizer: heap-use-after-free по адресу 0x61400000fe44 на pc 0x47b55f bp 0x7ffc36b28200 sp 0x7ffc36b281f8ЧТЕНИЕ размера 4 в 0x61400000fe44 поток T0 #0 0x47b55e в главном /home/test/example_UseAfterFree.cc:5 #1 0x7f15cfe71b14 в __libc_start_main (/lib64/libc.so.6+0x21b14) #2 0x47b44c в _start (/root/a.out+0x47b44c)0x61400000fe44 расположен на 4 байта внутри 400-байтовой области [0x61400000fe40,0x61400000ffd0)освобождено потоком T0 здесь: #0 0x465da9 в операторе delete[](void*) (/root/a.out+0x465da9) #1 0x47b529 в главном /home/test/example_UseAfterFree.cc:4ранее выделено потоком T0 здесь: #0 0x465aa9 в операторе new[](unsigned long) (/root/a.out+0x465aa9) #1 0x47b51e в основном /home/test/example_UseAfterFree.cc:3РЕЗЮМЕ: AddressSanitizer: heap-use-after-free /home/test/example_UseAfterFree.cc:5 mainТеневые байты вокруг ошибочного адреса: [...] 0x0c287fff9fb0: фа фа фа фа фа фа фа фа фа фа фа фа фа фа фа=>0x0c287fff9fc0: фа фа фа фа фа фа фа фа[fd]fd fd fd fd fd fd fd 0x0c287fff9fd0: фд фд фд фд фд фд фд фд фд фд фд фд фд фд фд фд фд [...]Легенда теневых байтов (один теневой байт представляет 8 байтов приложения): Адресуемый: 00 Частично адресуемый: 01 02 03 04 05 06 07 Куча слева redzone: fa Куча правая красная зона: fb Освобожденная область кучи: fd Стек левая красная зона: f1 Стек в середине красной зоны: f2 Стек правая красная зона: f3 Стек частичной красной зоны: f4 Стек после возврата: f5 Использование стека после области действия: f8 Глобальная красная зона: f9 Глобальный порядок инициализации: f6 Отравлен пользователем: f7 ASan внутренний: fe==5587==ПРЕРЫВАНИЕ
// ЗАПУСК: clang++ -O -g -fsanitize=адрес heap-buf-of.cc && ./a.outint main ( int argc , char ** argv ) { int * массив = новый int [ 100 ]; массив [ 0 ] = 0 ; int res = array [ argc + 100 ]; // БАБАХ удалить [] массив ; возврат рез ; }
==25372==ОШИБКА: AddressSanitizer: переполнение буфера кучи по адресу 0x61400000ffd4 на компьютере 0x0000004ddb59 bp 0x7fffea6005a0 sp 0x7fffea600598ЧТЕНИЕ размера 4 в 0x61400000ffd4 поток T0 #0 0x46bfee в главном /tmp/main.cpp:4:130x61400000ffd4 расположен на 4 байта правее 400-байтовой области [0x61400000fe40,0x61400000ffd0)выделено потоком T0 здесь: #0 0x4536e1 в операторе delete[](void*) #1 0x46bfb9 в основном /tmp/main.cpp:2:16
// ЗАПУСК: clang -O -g -fsanitize=адрес стек-буфера-из-.cc && ./a.outint main ( int argc , char ** argv ) { int stack_array [ 100 ]; стековый_массив [ 1 ] = 0 ; return stack_array [ argc + 100 ]; // БАБАХ }
==7405==ОШИБКА: AddressSanitizer: переполнение буфера стека по адресу 0x7fff64740634 на компьютере 0x46c103, процессор 0x7fff64740470, процессор 0x7fff64740468ЧТЕНИЕ размера 4 в 0x7fff64740634 поток T0 #0 0x46c102 в основном /tmp/example_StackOutOfBounds.cc:5Адрес 0x7fff64740634 находится в стеке потока T0 по смещению 436 в кадре #0 0x46bfaf в основном /tmp/example_StackOutOfBounds.cc:2 В этом кадре 1 объект(ов): [32, 432) 'stack_array' <== Доступ к памяти по смещению 436 приводит к переполнению этой переменной
// ЗАПУСК: clang -O -g -fsanitize=адрес global-buf-of.cc && ./a.out int global_array [ 100 ] = { -1 }; int main ( int argc , char ** argv ) { return global_array [ argc + 100 ]; // БАХ }
==7455==ОШИБКА: AddressSanitizer: глобальное переполнение буфера по адресу 0x000000689b54 на компьютере 0x46bfd8 bp 0x7fff515e5ba0 sp 0x7fff515e5b98ЧТЕНИЕ размера 4 в 0x000000689b54 поток T0 #0 0x46bfd7 в основном /tmp/example_GlobalOutOfBounds.cc:40x000000689b54 расположен на 4 байта правее глобальная переменная 'global_array' из 'example_GlobalOutOfBounds.cc' (0x6899c0) размером 400
// ВЫПОЛНЕНИЕ: g++ -O -g -fsanitize=null null-dereference.c && ./a.out int main ( int argc , char ** argv ) { const char * ptr = nullptr ; return * ptr ; // БАХ }
null-dereference.c:4:10: ошибка выполнения: загрузка нулевого указателя типа 'const char'Ошибка сегментации (сброс керна)
{{cite web}}
: |last1=
имеет общее название ( помощь )Эта функция позволяет использовать один из следующих sanitizers: [...] ControlFlowIntegrity LLVM Control Flow Integrity
-f[no-]sanitize=check1,check2,... Включить проверки времени выполнения для различных форм неопределенного или подозрительного поведения