我们的软件中有一个错误,结果很可怕:
The futex facility returned an unexpected error code.
我们将其追溯到一个问题,即 std::condition_variable 在 malloc 内存区域中的位置导致 futex 错误。如果 std::condition_variable 未在 16 字节字上对齐 - 那么当您尝试 wait
时它会导致 futex 错误。在示例中,前两个 wait_for
调用有效,但最后一个调用中止程序并出现 futex 错误。
void futex_error()
{
/* init */
std::mutex mtx;
/* Normal one works */
std::cout << "Doing normal" << "\n";
std::condition_variable* con_var = (std::condition_variable*)malloc(sizeof(std::condition_variable));
new (con_var) std::condition_variable{};
{
std::unique_lock<std::mutex> lck(mtx);
con_var->wait_for(lck, std::chrono::seconds(1));
}
/* Clean */
con_var->std::condition_variable::~condition_variable();
free(con_var);
std::cout << "Doing 16 bytes" << "\n";
/* Works on 16 byte alignment */
uint8_t* ptr_16 = (uint8_t*)malloc(sizeof(std::condition_variable) + 16);
std::condition_variable* con_var_16 = new (ptr_16 + 16) std::condition_variable{};
{
std::unique_lock<std::mutex> lck(mtx);
con_var_16->wait_for(lck, std::chrono::seconds(1));
}
/* Clean */
con_var_16->std::condition_variable::~condition_variable();
free(ptr_16);
std::cout << "Doing 1 byte" << "\n";
/* Futex error */
uint8_t* bad_ptr = (uint8_t*)malloc(sizeof(std::condition_variable) + 1);
std::condition_variable* bad = new (bad_ptr + 1) std::condition_variable{};
{
std::unique_lock<std::mutex> lck(mtx);
bad->wait_for(lck, std::chrono::seconds(1)); //<--- error here?
}
/* Clean */
bad->std::condition_variable::~condition_variable();
free(con_var);
}
我似乎无法找到有关 futex 错误的文档以及对齐会导致此错误的原因。有谁知道为什么会发生这种情况?这是在 linux(Arch 和 Ubuntu)上,同时使用 gcc 9.3。
最佳答案
why the alignment would cause this
Object types have alignment requirements ([basic.fundamental], [basic.compound]) which place restrictions on the addresses at which an object of that type may be allocated.
表达式:
new (bad_ptr + 1) std::condition_variable{};
在 bad_ptr + 1
未与 alignof(std::condition_variable)
对齐的系统上调用未定义的行为。在 godbolt 上测试对于 gcc10,alignof(std::confition_variable)
等于 8
。
bad->
访问都是未对齐的访问,都是未定义的行为。
Does anyone know why this would occur?
检查可执行文件执行时的 strace
输出,我们可以看到:
futex(0x557da3e262e9, FUTEX_WAIT_BITSET_PRIVATE, 0, {tv_sec=2439, tv_nsec=619296657}, FUTEX_BITSET_MATCH_ANY) = -1 EINVAL (Invalid argument)
因为 uaddr
第一个参数应该是指向 futex
调用的 int
的指针没有与 _Alignof(int)< 对齐
,内核检测到它 here和 futex 返回 EINVAL
。然后标准库就退出应用程序,这对于未定义的行为来说是一个非常好的行为。
关于c++ - std::condition_variable 的内存位置可能导致 futex 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62058325/