Член класса std::string поврежден строковым литералом, зарегистрированным сторонним макросом
Резюме:
У меня есть класс, реализующий разделяемую память с использованием Boost Interprocess. Ошибка сегментации происходит из метода read()
который получает доступ к named_condition
, Когда я смотрю на значения поблизости std::string
Члены класса в ГБД они тоже испорчены. Один содержит значение строкового литерала, который я регистрирую только через сторонний макрос.
Я собираюсь описать проблему, показать вам код, который устанавливает предполагаемые строковые значения, а затем спросить, являюсь ли я причиной проблемы, или это сторонний регистратор?
Я использую Clang (не GCC).
Эту проблему невероятно сложно воспроизвести. Это происходит один раз каждые 300+ запусков.
Подробности:
Это мой объект, содержащий Boost Interprocess named_condition и рядом std::string
s, которые я заметил, имели искаженные значения:
char a[1000];
std::shared_ptr<bip::named_mutex> mutex{nullptr};
char b[1000];
MyVector* vec{nullptr};
std::shared_ptr<bip::managed_shared_memory> segment{nullptr};
std::shared_ptr<bip::named_condition> cond_empty; // Seg fault
bool destroy_memory{false};
std::string shared_vector_name; // Weird value
std::string shared_mutex_name; // Weird value
std::string shared_cv_name; // Weird value
std::string shared_memory_name; // Weird value
std::string tag_name;
Два массива символов были добавлены несколько недель назад для обнаружения (вероятно, того же самого) сбоя сегментации.
Ошибка сегментации возникает, когда я пытаюсь получить доступ к named_condition при попытке прочитать общую память:
std::vector<T> read(const bool clearAfterReading, const bool readImmediately = false)
{
checkMemory(); // Loops over 'a' and checks for corruption
std::vector<T> readItems;
std::cout << "Reader trying to obtain mutex" << std::endl;
bip::scoped_lock<bip::named_mutex> lock(*sdc.mutex);
if(sdc.vec->empty() && readImmediately == false)
{
std::cout << "Reader waiting. vec size: " << sdc.vec->size() << std::endl;
sdc.cond_empty->wait(lock); //SEG FAULT OCCURS HERE
Когда я смотрю на состояние sdc.cond_empty в GDB, я замечаю m_base = 0x0
:
(gdb) p *(sdc.cond_empty._M_ptr)
$12 = {m_cond = {m_shmem = {<boost::interprocess::ipcdetail::managed_open_or_create_impl_device_holder<false, boost::interprocess::shared_memory_object>> = {<No data fields>}, static ManagedOpenOrCreateUserOffset = 16,
m_mapped_region = {m_base = 0x0, m_size = 104, m_page_offset = 0, m_mode = boost::interprocess::read_write, m_is_xsi = false}}}}
поэтому я предполагаю, что я прав, что это named_condition было повреждено?
Затем я решил проверить значения окружающих членов класса std::string (прокрутите вправо до конца):
(gdb) p sdc.shared_vector_name
$22 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff80a0d438 "HandleRunRequest()"}}
(gdb) p sdc.shared_mutex_name
$23 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff80a0d468 "File exists"}}
(gdb) p sdc.shared_cv_name
$24 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff80a0d498 "/abc_shared_memory"}}
(gdb) p sdc.shared_memory_name
$25 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff80a0d408 ""}}
(gdb) p sdc.tag_name
$26 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fffc021d598 "abc"}}
и я замечаю, что их значения совершенно неверны. Похоже, что значения получены из строковых литералов, которые я записываю через сторонний макрос.
Предполагаемые значения std::string устанавливаются с помощью следующего кода:
Это const:
extern "C"
{
const std::string ABC_SH_MEM_NAME = "abc";
}
передается через конструктор чтения общей памяти:
sharedMemReader(CONSTS::ABC_SH_MEM_NAME, CONSTS::ABC_SH_MEM_SIZE, true),
через аргумент тега:
SharedDataReader(const std::string& tag, const int numBytes, const bool destroyMemory)
{
sdc.initialise(tag, numBytes, destroyMemory);
так что жестко закодированные строки могут быть добавлены к tag
и назначается вышеупомянутым членам класса string:
void initialise(const std::string& tag, const int numBytes, const bool ownMemory)
{
std::cout << std::endl << "Started initialisation..." << std::endl;
const std::string sharedMemoryName = tag + "_shared_memory";
const std::string sharedVectorName = tag + "_shared_vector";
const std::string sharedMutexName = tag + "_shared_mutex";
const std::string sharedCVName = tag + "_shared_cv";
tag_name = tag;
shared_memory_name = sharedMemoryName;
shared_mutex_name = sharedMutexName;
shared_vector_name = sharedVectorName;
shared_cv_name = sharedCVName;
destroy_memory = ownMemory;
Как упоминалось ранее, shared_vector_name
поврежден значением "HandleRunRequest()".
Мое единственное использование этой строки / значения - это вызов стороннего макроса регистрации:
void MyClass::HandleRunRequest()
{
THIRD_PARTY_LOG_MACRO("HandleRunRequest()");
но этот метод не вызывается сразу-рядом read()
где происходит ошибка сегмента. Этот метод вызывает несколько других методов перед созданием нового потока, который затем вызывает read()
,
Могу ли я что-нибудь сделать, чтобы вызвать эту коррупцию? Или стороннее ведение журнала хранит значения в случайных адресах указателя?
У меня все еще есть дамп ядра и библиотека, но учтите, что эту проблему невероятно сложно воспроизвести.