We had a bug in our software that ended in the dreaded:
The futex facility returned an unexpected error code.
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. If the std::condition_variable is not aligned on a 16 byte word - then it causes the futex error when you try to wait. In the example the first two wait_for calls work, but the last one aborts the program with the futex error.
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. Does anyone know why this would occur? This is on linux (Arch and Ubuntu) whilst using gcc 9.3.