В этом документе показано, как включить специальные инструменты отладки при использовании AGDE. Эти инструменты могут помочь в устранении трудно диагностируемых повреждений памяти и ошибок перезаписи.
HWAddress Sanitizer и Address Sanitizer
HWAddress Sanitizer (HWASan) и Address Sanitizer (ASan) — это инструменты отладки повреждений памяти, которые помогают отлаживать повреждения памяти и ошибки перезаписи, например следующие:
- Переполнение и опустошение буфера стека
- Переполнение и опустошение буфера кучи
- Использование стека за пределами его области применения
- Двойные бесплатные и дикие бесплатные ошибки
- Использование стека после возврата (только HWASan)
Мы рекомендуем включать HWASan или ASan только при отладке проблемы или в рамках автоматического тестирования. Хотя эти инструменты эффективны, их использование влечет за собой штраф.
Поведение во время выполнения
Если этот параметр включен, и HWASan, и ASan автоматически проверяют наличие повреждений памяти в вашем приложении.
Если обнаруживается ошибка памяти, приложение аварийно завершает работу с ошибкой SIGBART
(прерывание сигнала) и печатает подробное сообщение в logcat. Копия сообщения также записывается в файл /data/tombstones
.
Сообщение об ошибке выглядит примерно так:
ERROR: HWAddressSanitizer: tag-mismatch on address 0x0042a0826510 at pc 0x007b24d90a0c
WRITE of size 1 at 0x0042a0826510 tags: 32/3d (ptr/mem) in thread T0
#0 0x7b24d90a08 (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x2a08)
#1 0x7b8f1e4ccc (/apex/com.android.art/lib64/libart.so+0x198ccc)
#2 0x7b8f1db364 (/apex/com.android.art/lib64/libart.so+0x18f364)
#3 0x7b8f2ad8d4 (/apex/com.android.art/lib64/libart.so+0x2618d4)
0x0042a0826510 is located 0 bytes to the right of 16-byte region [0x0042a0826500,0x0042a0826510)
allocated here:
#0 0x7b92a322bc (/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so+0x212bc)
#1 0x7b24d909e0 (/data/app/com.example.hellohwasan-eRpO2UhYylZaW0P_E0z7vA==/lib/arm64/libnative-lib.so+0x29e0)
#2 0x7b8f1e4ccc (/apex/com.android.art/lib64/libart.so+0x198ccc)
Предварительные условия
Требования ХВАСан
Чтобы использовать HWAsan:
- Вы должны использовать AGDE 24.1.99 или выше.
- Приложение должно быть создано с использованием NDK 26 или более поздней версии.
- Приложение должно быть создано с использованием целевого SDK 34 или более поздней версии.
- Целью должно быть устройство
arm64-v8a
под управлением Android 14 (уровень API 34) или выше.
Используйте общую стандартную библиотеку C++ в своем проекте.
Из-за известной проблемы ASan несовместим с обработкой исключений C++ при использовании libc++_static
. Эта проблема не наблюдается при использовании libc++_shared
.
HWASan имеет собственную реализацию операторов new
и delete
, которую нельзя использовать, если стандартная библиотека статически скомпонована с проектом.
Чтобы изменить этот параметр, см. раздел «Связывание стандартной библиотеки C++» этого документа.
Включить генерацию указателя кадра
HWASan и ASan используют быстрый механизм размотки на основе указателя кадра для создания информации трассировки стека для событий выделения и освобождения памяти. Это означает, что для использования этих функций необходимо включить генерацию указателя кадра в настройках компилятора C++. То есть вам нужно отключить оптимизацию пропуска указателя кадра.
Чтобы изменить этот параметр, см. раздел «Включение генерации указателя кадра» этого документа.
Настройка проекта Visual Studio для использования HWASan или ASan
Включение HWASan или ASan
Чтобы включить HWASan или ASan, перейдите в раздел «Свойства конфигурации» > «Общие» на страницах свойств вашего проекта.
Рис. 1. Параметр « Свойства проекта» в окне обозревателя решений Visual Studio.
Рис. 2. Параметр Address Sanitizer (ASan) в общих свойствах проекта.
Чтобы включить HWASan для вашего проекта, измените параметр Address Sanitizer (ASan) на Hardware ASan Enabled (fsanitize=hwaddress) .
Чтобы включить ASan для вашего проекта, измените настройку Address Sanitizer (ASan) на ASan Enabled (fsanitize=address) .
Включение генерации указателя кадра
Генерация указателя фрейма контролируется настройкой компилятора Omit Frame Pointer C/C++, которую можно найти на страницах свойств вашего проекта в разделе Свойства конфигурации > C/C++ > Оптимизация .
Рис. 3. Где находится параметр «Опустить указатель кадра» .
При использовании HWASan или ASan установите для параметра «Опустить указатель кадра» значение «Нет» (-fno-omit-frame-pointer) .
Связывание стандартной библиотеки C++ в режиме общей библиотеки
Параметр режима компоновщика для стандартной библиотеки C++ можно найти на страницах свойств вашего проекта в разделе «Свойства конфигурации» > «Общие» в разделе « Параметры проекта по умолчанию» .
Рис. 4. Где найти настройку режима компоновщика для стандартной библиотеки C++.
При использовании HWASan или ASan установите для параметра «Использование STL» значение «Использовать стандартные библиотеки C++ (.so)» . Это значение связывает стандартную библиотеку C++ с вашим проектом как общую библиотеку , необходимую для правильной работы HWASan и ASan.
Создание конфигурации сборки для использования Address Sanitizer
Если вы предпочитаете временно использовать HWASan или ASan, возможно, вам не захочется создавать новую конфигурацию сборки исключительно для их использования. Это может быть тот случай, если ваш проект небольшой, вы изучаете эту функцию или реагируете на проблему, обнаруженную во время тестирования.
Однако, если вы считаете это полезным и планируете использовать его регулярно, вы можете рассмотреть возможность создания новой конфигурации сборки для HWASan или ASan, как показано в примере Teapot . Вы можете сделать это, если, например, вы регулярно запускаете Address Sanitizer в рамках модульных тестов или во время ночных дымовых тестов вашей игры.
Создание отдельной конфигурации сборки может быть особенно полезно, если у вас есть большой проект, который использует большое количество различных сторонних библиотек, которые вы обычно статически связываете со стандартной библиотекой C++. Специальные конфигурации сборки помогут гарантировать, что настройки вашего проекта всегда будут точными.
Чтобы создать конфигурацию сборки, на страницах свойств вашего проекта нажмите кнопку «Диспетчер конфигураций…» , а затем откройте раскрывающийся список «Конфигурация активного решения» . Затем выбор
Использование HWAsan с настраиваемыми распределителями памяти
HWASan автоматически перехватывает память, выделенную через malloc
(или new
), чтобы можно было вставлять теги в указатели и проверять несоответствие тегов.
Однако при использовании специального распределителя памяти HWASan не может автоматически перехватывать ваши собственные методы распределения памяти. Поэтому, если вы хотите использовать HWASan со своим настраиваемым распределителем памяти, настройте свой распределитель памяти на явный вызов HWASan. Это можно сделать с помощью всего нескольких строк кода.
Предварительные условия
Методы HWAsan, которые вам нужно вызвать, определены в этом заголовке:
#include "sanitizer/hwasan_interface.h"
Инструментируйте свой метод распределения памяти
Выделяйте объекты с степенью детализации и выравнивания 16-байтовых блоков. Например, если у вас есть распределитель пула, который обслуживает объекты фиксированного размера размером 24 байта, округлите выделение до 32 байтов и выровняйте до 16 байт.
Создайте 8-битный тег. Ваш тег не должен использовать значения от 0 до 16, поскольку эти значения зарезервированы для внутреннего использования.
Включите HWAsan, чтобы начать отслеживать область памяти с помощью этого тега:
__hwasan_tag_memory((void*) address, tag, size);
Вставьте тег в верхние 8 бит вашего указателя:
address = __hwasan_tag_pointer((void*) address, tag);
Инструментируйте свой метод освобождения памяти
Сбросьте тег для области памяти, чтобы дальнейший доступ через существующие указатели с тегами не удался:
__hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), 0, size);
Работа с заранее выделенным пулом объектов
Если ваш распределитель памяти предварительно выделяет объекты в пуле и возвращает объекты обратно в пул вместо того, чтобы фактически освободить их, то ваш метод освобождения может напрямую перезаписать тег для памяти и указатель новым значением:
```
__hwasan_tag_memory(__hwasan_tag_pointer(ptr, 0), tag, size);
ptr = __hwasan_tag_pointer((void*)ptr, tag);
```
Если вы используете этот метод, вашим методам выделения не нужно помечать указатели или блоки памяти, а помечать указатели и блоки памяти при предварительном выделении объектов в пуле. См. пример PoolAllocator для примера использования этого стиля.