0Pricing
C++ Academy · 课时

UBSan 与 TSan

查找未定义行为和竞态

UBSan 与 TSan 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。

另外两种检测器

除了 ASan 外,还有两种检测器分别针对不同类别的错误。

  • UBSan:未定义行为(溢出、错误移位、空指针解引用)
  • TSan:多线程代码中的数据竞争

启用 UBSan

使用 -fsanitize=undefined 启用 UndefinedBehaviorSanitizer。它可以与 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 可以标记许多隐蔽的错误。

  • 超出范围的移位(对于 32 位整数,x << 40)
  • 空指针解引用
  • 未对齐访问
  • 无效的枚举值或布尔值

让 UBSan 遇错即停

默认情况下,UBSan 输出信息后会继续执行。加入 -fno-sanitize-recover=undefined,即可在第一个错误处中止,这更适合持续集成。

g++ -fsanitize=undefined -fno-sanitize-recover=undefined -g main.cpp -o app

启用 TSan

使用 -fsanitize=thread 启用 ThreadSanitizer。它可以检测数据竞争:两个线程在没有同步的情况下访问同一块内存,且至少有一个线程执行写入。

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。

检测器构建矩阵

一种实用的持续集成配置是在两种检测器构建中运行测试套件。

  • 构建 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」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。

「UBSan 与 TSan」这节课中我会学到什么?

查找未定义行为和竞态 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C++ Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「UBSan 与 TSan」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C++ Academy 课中编写并运行代码吗?

能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 gdb 和 lldb
  2. AddressSanitizer
  3. UBSan 与 TSan
  4. Valgrind 基础
← 返回 C++ Academy