UBSan и TSan
Находите неопределённое поведение и гонки
«UBSan и TSan» — бесплатный урок C++ Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Ещё два санитайзера
Помимо ASan, два санитайзера предназначены для других классов ошибок.
- UBSan: неопределённое поведение (переполнение, некорректные сдвиги, разыменование нулевого указателя)
- TSan: гонки данных в многопоточном коде
Включение UBSan
UndefinedBehaviorSanitizer включается с помощью -fsanitize=undefined. Его можно сочетать с ASan.
g++ -fsanitize=undefined -g main.cpp -o app
./appПереполнение знакового целого числа
Переполнение знакового целого числа в C++ является неопределённым поведением. UBSan сообщает о нём точно в соответствующей строке.
#include <climits>
#include <iostream>
int main() {
int x = INT_MAX;
int y = x + 1; // signed overflow: UB
std::cout << y << "\n";
return 0;
}Другие ошибки неопределённого поведения, обнаруживаемые UBSan
UBSan обнаруживает множество трудноуловимых ошибок.
- Сдвиги за пределы диапазона (
x << 40для 32-разрядного целого числа) - Разыменование нулевого указателя
- Невыровненный доступ
- Недопустимые значения перечислений или логических переменных
Остановка UBSan при ошибке
По умолчанию UBSan выводит сообщение и продолжает выполнение. Добавьте -fno-sanitize-recover=undefined, чтобы прервать выполнение при первой ошибке; для CI это лучше.
g++ -fsanitize=undefined -fno-sanitize-recover=undefined -g main.cpp -o appВключение TSan
ThreadSanitizer включается с помощью -fsanitize=thread. Он обнаруживает гонки данных: два потока обращаются к одной и той же памяти без синхронизации, причём хотя бы один из них выполняет запись.
g++ -fsanitize=thread -g main.cpp -o app -pthread
./appПример гонки данных
Два потока увеличивают общий счётчик без блокировки. TSan сообщает о конфликтующих обращениях и их стеках.
#include <thread>
#include <iostream>
int counter = 0;
void work() { for (int i = 0; i < 1000; ++i) ++counter; }
int main() {
std::thread t1(work), t2(work);
t1.join();
t2.join();
std::cout << counter << "\n";
return 0;
}Исправление гонки
Защищайте общие данные мьютексом или используйте std::atomic. После исправления TSan не сообщает о гонках.
#include <thread>
#include <atomic>
#include <iostream>
std::atomic<int> counter{0};
void work() { for (int i = 0; i < 1000; ++i) ++counter; }
int main() {
std::thread t1(work), t2(work);
t1.join();
t2.join();
std::cout << counter << "\n";
return 0;
}Совместимость TSan и ASan
TSan нельзя сочетать с ASan в одной сборке (они конфликтуют). Используйте отдельные конфигурации сборки: одну для ASan+UBSan, другую — для TSan.
Матрица сборок с санитайзерами
Практическая настройка CI запускает набор тестов в двух сборках с санитайзерами.
- Сборка A:
-fsanitize=address,undefined - Сборка B:
-fsanitize=thread
Это позволяет обнаруживать ошибки памяти, неопределённого поведения и многопоточности.
Затраты и ограничения
TSan может замедлять программы в 5–15 раз и потреблять значительно больше памяти. Как и все санитайзеры, он обнаруживает ошибки только на выполняемых путях кода, поэтому хорошие многопоточные тесты имеют большое значение.
Быстрая проверка
Вспомните, что обнаруживает TSan.
Повторение
Вы изучили UBSan и TSan.
- UBSan (
-fsanitize=undefined) обнаруживает переполнения, некорректные сдвиги и разыменование нулевого указателя - Используйте
-fno-sanitize-recover, чтобы прервать выполнение при первой ошибке неопределённого поведения - TSan (
-fsanitize=thread) обнаруживает гонки данных; исправляйте их с помощью мьютекса или атомарных операций - TSan и ASan требуют отдельных сборок
Часто задаваемые вопросы
Урок «UBSan и TSan» бесплатный?
Да — полный текст урока «UBSan и TSan» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «UBSan и TSan»?
Находите неопределённое поведение и гонки Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «UBSan и TSan»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.