1

像 libstdc++ 一样,我们在某些地方检查abi::__forced_unwind,然后重新抛出它,而不是采取其他行动。像 libstdc++ 一样,我们通过引用来捕获它:

try {
    /* ... */
} catch (abi::__forced_unwind&) {
    throw;
} catch (...) {
    /* ... */
} 

但是如果我们真的 pthread_cancel 来执行代码,ubsan 会抱怨:

运行时错误:引用绑定到“struct __forced_unwind”类型的空指针

在这里,我们是通过 const-ref 还是通过 mutable ref 捕获并不重要。

我们(和 libstdc++)是否真的在这里遇到了 UB,或者它是 GCC 的 UBSan 实现中的误报?

4

1 回答 1

4

这是强制展开实现中的一个错误,已在 GCC Bugzilla 中作为票证#100415 提交。(可以说它应该在 GCC 本身中修复,因为您没有创建实际的引用绑定,只匹配异常类型。)

在修复它的同时,您可以catch使用属性装饰包含子句的函数[[gnu::no_sanitize("null")]],这将禁止对引用进行空检查,仅此而已:

#include <pthread.h>
#include <cxxabi.h>
#include <iostream>

int main() {
    pthread_t thrd;

    pthread_create(
        &thrd, nullptr,
        [] [[gnu::no_sanitize("null")]] (void *) -> void * {
            try {
                pthread_exit(nullptr);
            } catch (abi::__forced_unwind const &fu) {
                std::cerr << "forced unwind with " << &fu << std::endl;

                // does not trigger UBSan
                int &x = *static_cast<int *>(nullptr);
                // triggers UBSan
                1 / 0;

                throw;
            }
        }, nullptr);
    pthread_join(thrd, nullptr);

    // triggers UBSan
    int &x = *static_cast<int *>(nullptr);

    return 0;
}
于 2021-12-20T23:07:53.327 回答