I received the following code from a colleague, broken down to the bare minimum, using Boost::Signal2 and lambda expressions. It compiles with g++ 6.x and g++ 5.4.1 (the latter with argument -std=c++11).
It should print i: 5 (should be 5)
Using a gcc 6.4.1 (or 6.1.1) cross compiler for arm32 (arm-cortexa15-linux-gnueabihf-g++) and running on such a system, the output is i: 0 (should be 5)
Other architectures (x86_64) and compilers (gcc 5.4.1) work as expected.
When I change to code to use a signal instead of a slot, everything is ok.
My questions are:
Is this code really reliably supposed to output i: 5 (should be 5), or is this code buggy and worked only accidentally?
Or is there a bug in the ARM32 gcc6 compiler? (gcc 5 works)
Code:
#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();
}
Compile and run delivers the following output:
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)
That looks like a bug.
Can you reduce the reproducer? Say,
what happens if you disable optimizations
what happens if you remove the LogBuffer?
What happens if you remove the slot and use it as a signal
What happens if you keep the signals stuff and just invoke the lambda directly?
What happens if you invoke the lambda before creating the slot
What happens if you don't even create the slot, and call the lambda directly?
What happens if you further also remove the signals2 header.
What happens if you terminate in the assert handlers (perhaps you are getting asserts at a time when std::cout
is not yet initialized//available)
If you reduce it to the simplest possible core and still have the failure, you will at least know whether to file a bug at Boost or GCC