c++ - std::condition_variable 的内存位置可能导致 futex 错误

标签 c++ memory-management memory-alignment

我们的软件中有一个错误,结果很可怕:

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

来自 C++ draft 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.

表达式:

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/

相关文章:

c++ - 有没有办法为所有堆 userptr 获取 userstack

c - 用于确定处理器如何在某些位中存储整数的公式

c++ - std::allocator 怎么这么快?

c++ - 分配给 new 的内存是否会自动释放?

c - 在 PowerPC 中生成未对齐的内存访问异常

c++ - 返回 const 引用是否更有效

c++ - 如何添加一个整数的所有数字直到它是一位数字?

c++ - operator<< 重载、 namespace 和模板

c++ - 在类型化的 std::array 中放置 new 和 std::destroy_at 的安全性?

c - 为什么必须在 typedef 中指定此对齐属性?