У меня есть фрагмент кода, который выполняется в цикле выполнения ROS с 3 лямбдами - два для изменения флагов и один для вызова цикла выполнения ROS, пока темы не достигают определенного условия. По существу близко к
bool wait_until_engine_started()
{
bool engine_started_state = false;
bool engine_started_event = false;
// Psuedocode for a subscription wrapper which invokes the below lambda
auto engine_state_checker =
[&](const EngineRosMessage::ConstPtr& msg) {
// Psuedocode for a validation function
if (engine_appears_to_be_on(msg))
{
// Modify the referenced boolean here
engine_started_state = true;
}
// Return to runloop
}
);
// Psuedocode for a subscription wrapper which invokes the below lambda
auto engine_code_checker =
[&](const DifferentEngineRosMessage::ConstPtr& msg) {
// Psuedocode for a validation function
if (engine_appears_to_be_on_via_different_method(msg))
{
// Modify the referenced boolean here
engine_started_event = true;
}
// Return to runloop
}
);
return utils::spin_until_condition([&](){
return engine_started_state && engine_started_event;
});
}
С
bool spin_until_condition(std::function<bool()> condition)
{
while(ros::ok() && !condition())
{
ros::spinOnce();
}
return ros::ok();
}
В некоторых случаях я сталкиваюсь с segfault с помощью лямбды, используемой в spin_until_condition
лямбда-выражениях, в некоторых случаях, когда включены определенные разделы кода, не связанные с этим разделом.
Зондирование в GDB показывает, что на моей машине
- на уровне декларации
engine_started_event
адрес engine_started_event
равен 0x7fffffffc3ff
- внутри лямбды
engine_code_checker
адрес engine_started_event
равен 0x7fffffffc3ff
- внутри rvalue lambda в
spin_until_condition
адрес engine_started_event
изначально 0x7fffffffc3ff
, но после engine_started_event = true
перемещается в 0x1007fffffffc3ff
, и в этот момент возникает ошибка segf
Это поведение очень надежно отключается удалением определенного блока кода, который не связан с этим блоком. Более того, вышеупомянутый раздел кода просматривается дважды - один раз перед блоком, вызывающим проблемы, и один раз после, причем проблема возникает только во втором раунде.
AFAIK - нет причины, по которой ссылка должна когда-либо менять свой адрес, и надежность удаления проблемного блока заставляет меня думать, что он ответственен, но я не могу понять, как они будут затронуты, учитывая, что логические значения и 3-я лямбда стек выделенных переменных.
Я запускаю это на gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)
- запуск этого на gcc-7
не вызвал segfault, из-за чего я заподозрил компилятор. Но я снова и снова узнал, что компилятор, как правило, довольно хорошо справляется со своей работой, и тот факт, что удаление нашего кода устраняет проблему, по-видимому, сильно указывает на наш код. Теперь я предполагаю, что неправильная запись в память в несвязанном коде приводит к некоторому изменению ссылки.
Valgrind также ничего не показывал, кроме фактического доступа к segfaulting на 0x1007fffffffc3ff
Итак - ТЛ; ДР
- Как адрес захвата ссылок лямбда может изменить свой адрес так, как он показывает выше (включая странные случаи плохого доступа к памяти)
- Существуют ли разумные способы отладки подобного рода ситуаций, чтобы я мог поймать нарушающий код, выполняя запись, где живет эта ссылка
- Или это компилятор whoopsie