什么会导致C ++引用更改其指向的地址

时间:2019-06-09 22:58:40

标签: c++ gcc lambda reference

我有一段代码在带有3个lambda的ROS Runloop中运行-两个用于修改标志,一个用于调用ROS Runloop,直到主题达到特定条件为止。本质上接近

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();
}

在某些情况下,当包含与本节无关的特定代码段时,在spin_until_condition lambda中使用了lambda时,我遇到了段错误。

在GDB中进行探测表明在我的机器上

  • engine_started_event声明级别,engine_started_event的地址为0x7fffffffc3ff
  • 在lambda engine_code_checker内,engine_started_event的地址为0x7fffffffc3ff
  • spin_until_condition的右值lambda中,engine_started_event的地址最初为0x7fffffffc3ff,但在engine_started_event = true之后,移至0x1007fffffffc3ff,此时发生段错误

通过删除与此块无关的特定代码块,可以非常可靠地禁用此行为。更进一步,以上代码段被遍历了两次-一次在导致问题的块之前,一次在此之后,而问题仅在第二轮发生。

AFAIK-没有理由引用应该更改其地址,并且删除问题块的可靠性使我认为它是负责任的,但是鉴于布尔值和第3个lambda是堆栈分配的变量。

我正在gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)上运行此命令-在gcc-7上运行此命令不会导致段错误,这使我怀疑编译器是怎么回事。但是我一次又一次地了解到,编译器通常可以很好地完成工作,而删除代码可以消除问题的事实似乎强烈地指向了我们的代码。我现在的猜测是,无关代码中的不良内存写入会导致引用以某种方式更改。

Valgrind除了在0x1007fffffffc3ff上进行实际的段错误访问外,也未显示任何相关内容

所以-TL; DR

  • lambda的引用捕获地址如何以上面显示的方式更改其地址(包括奇怪的内存访问不良情况)
  • 是否有任何明智的方法来调试这种情况,以便我可以在引用所在的位置进行写操作以捕获令人讨厌的代码
  • 或者这是编译器吗

1 个答案:

答案 0 :(得分:0)

这种行为可能是堆损坏。您要删除的似乎无关的块很可能正在访问不应访问的内存。检查循环以编写数组的边界,访问已删除的内存或两次删除。

可能发生的是这段代码覆盖了lambda对象生存的内存,并最终更改了其捕获的值。