Поделиться через


Теневые байты в AddressSanitizer

Кратко рассмотрим концепцию теневых байтов и способ их использования реализацией среды выполнения /fsanitize=address. Дополнительные сведения см. в документации по первоначальному исследованию AddressSanitizer — Serebryany, et al и текущей документации по алгоритму AddressSanitizer.

Основная концепция

Каждый 8 байт в виртуальном адресном пространстве приложения можно описать с помощью одного байта тени.

Один теневой байт описывает, сколько байтов сейчас доступно следующим образом:

  • 0 означает, что все 8 байт
  • 1-7 означает от 1 до семи байтов
  • Отрицательные числа кодируют контекст среды выполнения для создания отчетов диагностика.

Условные обозначения байтов тени

Рассмотрим эту легенду байтов тени, где определены все отрицательные числа:

Снимок экрана: условные обозначения теневых байтов AddressSanitizer.

Сопоставление — описание адресного пространства

Каждый 8 байт в виртуальном адресном пространстве приложения, выровненном "0-mod-8", можно сопоставить с теневым байтом, описывающим этот слот в виртуальном адресном пространстве. Это сопоставление можно выполнить с помощью простой смены и добавления.

В x86:

char shadow_byte_value = *((Your_Address >> 3) + 0x30000000)

В x64:

char shadow_byte_value = *((Your_Address >> 3) + _asan_runtime_assigned_offset)

Создание кода — тесты

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

ShadowAddr = (Addr >> 3) + Offset;
if (*ShadowAddr != 0) {
    ReportAndCrash(Addr);
}

При инструментировании ссылки на память, которая не превышает 8 байтов, инструментирование немного сложнее. Если теневое значение положительно (то есть только первые k байтов в 8-байтовом слове можно получить к доступу), необходимо сравнить последние 3 бита адреса с k.

ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k)) {
    ReportAndCrash(Addr);
}

Среда выполнения и созданный компилятором код записывают теневые байты. Эти теневые байты разрешают или отменяют доступ при освобождении областей или хранилища. Приведенные выше проверки считывают теневые байты, описывающие 8-байтовые "слоты" в адресном пространстве приложения в определенное время выполнения программы. Помимо этих явно созданных проверок среда выполнения также проверяет теневые байты после перехвата (или "перехватчиков") многих функций в CRT.

Дополнительные сведения см. в списке перехватанных функций.

Настройка теневых байтов

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

См. также

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