代码之家  ›  专栏  ›  技术社区  ›  Reiner Huober

Boost::在arm32上使用gcc6时,带有lambda表达式的Signals2插槽失败

  •  2
  • Reiner Huober  · 技术社区  · 7 年前

    我从一位同事那里收到了以下代码,使用Boost::Signal2和lambda表达式将代码分解到最低限度。它是用g++6编译的。x和g++5.4.1(后者带有参数-std=c++11)。

    应该打印出来 i: 5(应为5)

    使用gcc 6.4.1(或6.1.1)arm32交叉编译器(arm-cortexa15-linux-gnueabihf-g++),并在这样的系统上运行,输出是 i: 0(应为5)

    其他体系结构(x86\u 64)和编译器(gcc 5.4.1)工作正常。

    当我改为代码使用信号而不是插槽时,一切都正常。

    我的问题是:

    1. 这段代码真的应该可靠地输出i:5(应该是5),还是这段代码有错误,只是意外地工作?

    2. 或者ARM32 gcc6编译器中是否存在错误?(gcc 5工程)

    代码:

    #include <exception>
    #include <iostream>
    #include <boost/signals2.hpp>
    
    class LogBuffer : public std::streambuf
    {   
    public:
        LogBuffer()
        {   
        }   
    
        char m_buf[242 - 20];
    };  
    
    namespace boost
    {   
        void assertion_failed(char const * p_expr,
                              char const *,
                              char const *, long)
        {   
            std::cerr << "FAILED: " << p_expr << std::endl;
        }   
    
        void assertion_failed_msg(char const *,
                                  char const * msg,
                                  char const *,
                                  char const *, long)
        {   
            std::cerr << "FAILED: " << msg << std::endl;
        }   
    } // namespace boost
    
    void myfunction(void)
    {   
    
        {   
            LogBuffer b;
            std::cout << "LogBuffer size: " << sizeof(LogBuffer) << std::endl;
        }   
        int i=5;
        std::cout << i << std::endl;
        auto lambda = [i] { std::cerr << "i: " << i << " (should be 5)" << std::endl; };
        boost::signals2::signal<void()>::slot_type slot{lambda};
        slot();
    }   
    
    int main(int argc, char *argv[])
    {   
        myfunction();
    }   
    

    编译和运行提供以下输出:

    arm-cortexa15-linux-gnueabihf-g++ (GCC) 6.4.1 20170811
    Copyright (C) 2017 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
    Linux fctj-4a 4.4.109-g68c6f3c-fsm4_axm #1 SMP PREEMPT Fri Feb 2 05:37:09 UTC 2018 armv7l GNU/Linux
    
    LogBuffer size: 256
    5
    i: 0 (should be 5)
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   sehe    7 年前

    看起来像个虫子。

    你能缩小复制机吗?说

    • 如果禁用优化,会发生什么情况

    • 如果删除日志缓冲区会发生什么?

    • 如果卸下插槽并将其用作信号,会发生什么情况

    • 如果保留信号内容并直接调用lambda,会发生什么?

    • 如果在创建插槽之前调用lambda会发生什么情况

    • 如果您甚至不创建插槽,直接调用lambda,会发生什么?

    • 如果进一步删除signals2标头,会发生什么情况。

    • 如果在断言处理程序中终止,会发生什么情况(可能是在 std::cout 尚未初始化//可用)

    如果您将其简化为最简单的核心,但仍然存在故障,那么您至少会知道是在Boost还是在GCC中提交错误

        2
  •  0
  •   Reiner Huober    7 年前

    这是我已经做过的:

    1. -O0,-O1:bug未显示i:5(应为5)
    2. -O2:错误显示为0(应为5)
    3. 删除日志缓冲区:5(应为5)
    4. 使用信号:0应为5
    5. 直接调用lambda(5应该是5)
    6. 调用插槽后使用i(例如打印):5(应为5)
    7. 使用i[100]:第一个元素变为零,其他元素不受影响
    8. 使用x86\u 64编译器:5应该是5

    其他人也会效仿。我不确定如何轻松删除signals2标头

    雷纳

    推荐文章