[英]Memory location of a std::condition_variable can cause futex error
我們的軟件中有一個錯誤以可怕的方式結束:
futex 工具返回了意外的錯誤代碼。
我們將其追溯到一個問題,即 std::condition_variable 在 memory 的 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 錯誤的文檔以及為什么 alignment 會導致此錯誤。 有誰知道為什么會發生這種情況? 這是在 linux(Arch 和 Ubuntu)上,同時使用 gcc 9.3。
為什么 alignment 會導致這個
Object 類型有 alignment 要求([basic.fundamental],[basic.compound]),這些要求限制了可以分配該類型的 object 的地址。
表達方式:
new (bad_ptr + 1) std::condition_variable{};
在bad_ptr + 1
未與alignof(std::condition_variable)
對齊的系統上調用未定義行為。 使用 gcc10 在godbolt上測試alignof(std::confition_variable)
等於8
。
兩個bad->
訪問都是未對齊的訪問,並且都是未定義的行為。
有誰知道為什么會發生這種情況?
在執行可執行文件時檢查strace
output,我們可以看到:
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)
對齊,所以 kernel 在這里檢測到它並且 futex 返回EINVAL
。 標准庫然后退出應用程序,這是未定義行為的完美行為。
找出我這個版本的來源“futex 工具返回了一個意外的錯誤代碼。” 錯誤信息。
它只是由#pragma pack(1)引起的,沒有在其他一些不相關的源代碼中返回正常打包。 然后 std::condition_variable 被初始化並且在使用時出錯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.