Что может заставить ссылку C ++ изменить свой адрес - PullRequest
0 голосов
/ 10 июня 2019

У меня есть фрагмент кода, который выполняется в цикле выполнения 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

1 Ответ

0 голосов
/ 10 июня 2019

Такое поведение, вероятно, является кучей коррупции.Блок, который вы удаляете и который кажется несвязанным, скорее всего, обращается к памяти, которой он не должен.Проверьте свои циклы на запись границ массива, доступ к удаленной памяти или двойное удаление.

Вероятно, происходит то, что фрагмент кода перезаписывает память, в которой живет лямбда-объект, и в конечном итоге меняет свое захваченное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...