0Pricing
C++ Academy · Урок

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 — локальная установка не требуется.

Все уроки этого курса

  1. Использование gdb и lldb
  2. AddressSanitizer
  3. UBSan и TSan
  4. Основы Valgrind
← Назад к C++ Academy