简体   繁体   English

Memory std::condition_variable 的位置可能导致 futex 错误

[英]Memory location of a std::condition_variable can cause futex error

We had a bug in our software that ended in the dreaded:我们的软件中有一个错误以可怕的方式结束:

The futex facility returned an unexpected error code. futex 工具返回了意外的错误代码。

We traced it down to a problem where the location of std::condition_variable within a malloc'd region of memory causes a futex error.我们将其追溯到一个问题,即 std::condition_variable 在 memory 的 malloc 区域内的位置导致 futex 错误。 If the std::condition_variable is not aligned on a 16 byte word - then it causes the futex error when you try to wait .如果 std::condition_variable 未在 16 字节字上对齐 - 那么当您尝试wait时它会导致 futex 错误。 In the example the first two wait_for calls work, but the last one aborts the program with the futex error.在示例中,前两个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);
}

I cant seem to find documentation on futex errors and why the alignment would cause this.我似乎找不到有关 futex 错误的文档以及为什么 alignment 会导致此错误。 Does anyone know why this would occur?有谁知道为什么会发生这种情况? This is on linux (Arch and Ubuntu) whilst using gcc 9.3.这是在 linux(Arch 和 Ubuntu)上,同时使用 gcc 9.3。

why the alignment would cause this为什么 alignment 会导致这个

From C++ draft Alignment p1 :来自C++ 草稿 Alignment p1

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. Object 类型有 alignment 要求([basic.fundamental],[basic.compound]),这些要求限制了可以分配该类型的 object 的地址。

The expression:表达方式:

new (bad_ptr + 1) std::condition_variable{};

invokes undefined behavior on systems where bad_ptr + 1 is not aligned to alignof(std::condition_variable) .bad_ptr + 1未与alignof(std::condition_variable)对齐的系统上调用未定义行为。 Testing on godbolt with gcc10 the alignof(std::confition_variable) is equal to 8 .使用 gcc10 在godbolt上测试alignof(std::confition_variable)等于8

Both bad-> accesses are unaligned accesses and both are undefined behavior.两个bad->访问都是未对齐的访问,并且都是未定义的行为。

Does anyone know why this would occur?有谁知道为什么会发生这种情况?

Inspecting strace output on execution of the executable, we can see that:在执行可执行文件时检查strace output,我们可以看到:

futex(0x557da3e262e9, FUTEX_WAIT_BITSET_PRIVATE, 0, {tv_sec=2439, tv_nsec=619296657}, FUTEX_BITSET_MATCH_ANY) = -1 EINVAL (Invalid argument)

Because uaddr first argument which should be a pointer to int of futex call is not aligned to _Alignof(int) , kernel detects it here and futex return EINVAL .因为uaddr第一个参数应该是futex调用的指向int的指针,没有与_Alignof(int)对齐,所以 kernel 在这里检测到它并且 futex 返回EINVAL The standard library just exits the application then, which is a perfectly fine behavior for undefined behavior.标准库然后退出应用程序,这是未定义行为的完美行为。

Found out the source of my version of this "The futex facility returned an unexpected error code."找出我这个版本的来源“futex 工具返回了一个意外的错误代码。” error message.错误信息。

It was simply caused by #pragma pack(1) without returning to normal packing in some other unrelated source code.它只是由#pragma pack(1)引起的,没有在其他一些不相关的源代码中返回正常打包。 Then std::condition_variable was initialized and it errored on use.然后 std::condition_variable 被初始化并且在使用时出错。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM