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
This is what I already did:
-O0, -O1: bug does not show up i: 5 (should be 5)
-O2: bug shows up 0 (should be 5)
remove Logbuffer: 5 (should be 5)
using a signal Signal: 0 should be 5
calling lambda directly (5 should be 5)
using i after calling slot (e.g printing): 5 (should be 5)
using i[100]: first element becomes zero, others unaffected
using x86_64 compiler : 5 should be 5
Others will follow. I am not sure how I can easily remove the signals2 header
Reiner
Related
(Note: This problem occurs for me only when the compiler switch /arch:AVX is set. More at the bottom)
My gtest unit tests have done this for 7 years
ASSERT_EQ(-3.0, std::round(-2.5f)); // (Note the 'f' suffix)
According to cpp-reference, std::round is supposed to round AWAY from zero, right? Yet with the current release, this test just started failing. Am I missing something? All I did was update my Visual Studio 2022 to 17.4.3 My co-worker with 17.3.3 does not have this problem
EDIT: I don't know if the problem is GTEST and its macros or assumptions my unit test makes about equality. I put the following two lines of code into my test
std::cerr << "std::round(-2.5) = " << std::round(-2.5) << std::endl;
std::cerr << "std::round(-2.5f) = " << std::round(-2.5f) << std::endl;
They produce the following output. The second one is wrong, is it not?
std::round(-2.5) = -3
std::round(-2.5f) = -2
EDIT #2: As I note above, the only occurs when I set the compiler flag /arch:AVX If just create a console app and do not set the flag of if I explicitly set it to /arch:IA32, the problem goes away. But the question then becomes: Is this a bug or am I just not supposed to use that option?
This is a known bug, see the bug report on developercommunity, which is already in the "pending release" state.
For completeness/standalone sake, the minimal example from there is (godbolt):
int main()
{
std::cout << "MSVC version: " << _MSC_FULL_VER << '\n';
std::cout << "Round 0.5f: " << std::round(0.5f) << '\n';
std::cout << "Round 0.5: " << std::round(0.5) << '\n';
}
compiled with AVX or AVX2.
The correct output e.g. with MSVC 19.33 is
MSVC version: 193331631
Round 0.5f: 1
Round 0.5: 1
while the latest MSVC 19.34 outputs
MSVC version: 193431931
Round 0.5f: 0
Round 0.5: 1
My very simple code shows below
#include <iostream>
#include <stdalign.h>
int main() {
char array_char[2] = {'a', 'b'};
float array_float[2] = {1, 2};
std::cout << "alignof(array_char): " << alignof(array_char) << std::endl;
std::cout << "alignof(array_float): " << alignof(array_float) << std::endl;
std::cout << "address of array_char: " << (void *) array_char << std::endl;
std::cout << "address of array_float: " << array_float << std::endl;
}
The output of this code is
alignof(array_char): 1
alignof(array_float): 4
address of array_char: 0x7fff5e8ec580
address of array_float: 0x7fff5e8ec570
The results of alignof operator is under expectation, but the real addresses of the two arrays are not consistent with them. No matter how many times I tried, the addresses are always 16 bytes aligned.
I'm using gcc 5.4.0 on Ubuntu 16.04 with Intel CORE i5 7th Gen CPU.
I have found this patch.
This seems to have been a bug for x86_64 fixed in GCC 6.4.
The System V x86-64 ABI requires aggregate types (such as arrays and structs) to be aligned to at least 16 bytes if they are at least 16 bytes large. According to a comment in the ABI specification this is meant to facilitate use of SSE instructions.
GCC seem to have mistakenly applied that rule to aggregates of size 16 bits (instead of bytes) and larger.
I suggest you upgrade your compiler to a more recent GCC version.
This is however only an optimization issue, not a correctness one. There is nothing wrong with stricter alignment for the variables and (as with the mentioned SSE) overalignment may have performance benefits in some situations that outweight the cost of the wasted stack memory.
In version 6.1, ncurses introduce init_extended_pair to extend limit of possible color pairs above short limit.
In my experiment everything works till value 255. For values 256 and greater, there is no error, but foreground and background have default values. For values 32767 and greater function return error.
Program return:
COLOR_PAIRS: 65536
Error: 32767
What is the proper why to create large number of color pairs? In my case I need at least 65536 of them. (Tested on Ubuntu 19.04)
#include <iostream>
#include <ncurses.h>
// g++ main.cpp -l:libncursesw.so.6.1 -ltinfo
int main() {
initscr();
start_color();
std::cout << "COLOR_PAIRS: " << COLOR_PAIRS << std::endl;
init_extended_color(2, 999, 0, 0);
init_extended_color(3, 0, 999, 0);
int pair1 = 255;
if (init_extended_pair(pair1, 2, 3) == ERR)
std::cout << "Error: " << pair1 << std::endl;
attron(COLOR_PAIR(pair1));
mvprintw(2, 1, "pair255");
attroff(COLOR_PAIR(pair1));
int pair2 = 256;
if (init_extended_pair(pair2, 2, 3) == ERR)
std::cout << "Error: " << pair2 << std::endl;
attron(COLOR_PAIR(pair2));
mvprintw(3, 1, "pair256");
attroff(COLOR_PAIR(pair2));
int pair3 = 32767; // 2^15-1
if (init_extended_pair(pair3, 3, 2) == ERR)
std::cout << "Error: " << pair3 << std::endl;
attron(COLOR_PAIR(pair3));
mvprintw(4, 1, "pair32767");
attroff(COLOR_PAIR(pair3));
refresh();
getch();
endwin();
return 0;
}
Edit:
Regarding similar problem How to enable 32k color pairs in ncurses?. In my case COLOR_PAIRS return value 65536 not 256, more over question is from 2015, and init_extended_pair was added to library on 2017.04.01, and released in version 6.1 January 27, 2018. Despite this I rebuild libncursesw6 package with --enable-ext-colors (--enable-widec was already available), but I get same result.
Actually (running this against ncurses 6.1 development), I do not see a failure from init_extended_pair. At first glance, the problem appeared to be this chunk:
attron(COLOR_PAIR(pair3));
mvprintw(4, 1, "pair32767");
attroff(COLOR_PAIR(pair3));
Those attron/attroff are legacy functions. You should use attr_on and attr_off. The macro form of attron and attroff (which is normally used instead of the function) is
#define wattron(win,at) wattr_on(win, NCURSES_CAST(attr_t, at), NULL)
#define wattroff(win,at) wattr_off(win, NCURSES_CAST(attr_t, at), NULL)
But in either case, the data is the "same": what fits in attr_t (a 32-bit value). In some other functions, the color-pair is passed through separately, and ncurses 6.1 provides for passing pairs larger than 16-bits via the opts parameter. These particular functions aren't extended in that way.
However, your program is returning an error for init_extended_pair. That could be any of (a few) returns from _nc_init_pair, but the principal one uses ValidPair:
#define ValidPair(sp,pair) \
((sp != 0) && (pair >= 0) && (pair < sp->_pair_limit) && sp->_coloron)
To check this, I ran the code against current ncurses6, with TERM=xterm-256color and TERM=xterm-direct. Both worked, though the init_extended_color in the latter fails (as expected). I can see that failure by compiling ncurses with TRACE, and turning the trace on with NCURSES_TRACE=0x220. Here's a screenshot of the trace, for example:
The current code is available from the ncurses homepage (here). If you are able to reproduce the problem using current code, you might want to discuss it on the bug-ncurses mailing list. Otherwise (see mailing list), the Debian package is the reference for the version you are using.
I am quite new to boost, as well as to multithreading and launching application using libraries. For my desired funcitonality, I was recommended by colleague to use boost::process library.
But the documentation to this part of boost is quite insufficient, so I could not determine which function suits my task best by documentation. I therefore started to try several functions there, but non has all the desired properties.
However there is one I cannot figure out, how to properly use. I cannot even compile it, let alone run it. And the function is boost::process::async_system. I could not find anywhere on internet some step-by-step guide on how to use this function and what individual components mean and do.
Could someone explain to me in detail the individual arguments and template arguments of the function ? Or provide a link to a detailed manual?
I like the examples here: https://theboostcpplibraries.com/boost.thread-futures-and-promises
For example, look at example 44.16, they clearly show how to use async:
#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <iostream>
int accumulate()
{
int sum = 0;
for (int i = 0; i < 5; ++i)
sum += i;
return sum;
}
int main()
{
boost::future<int> f = boost::async(accumulate);
std::cout << f.get() << '\n';
}
Waiting happens at the get method, not before. You might use a non-waiting mechanism, too.
As for compiling, you need to first build boost. Building is explained in detail here: https://www.boost.org/doc/libs/1_62_0/more/getting_started/windows.html
Most parts of the library work header-only. For asio, building the binary libraries (also explained in the link) is necessary. In your project (i.e. visual studio projects, xcode project or just some make files), you need to set include and library headers of boost to use it. The link above helps with this as well.
I'm just ramping up on Boost.Process but the sample code I have working might be helpful here.
boost::process:async_system() takes 3 parameters: a boost::asio::io_context object, an exit-handler function, and the command you want to run (just like system(), and it can be either a single line or more than one arg).
After it's invoked, you use the io_context object from the calling thread to manage and monitor the async task - I use the run_one() method which will "Run the io_context object's event processing loop to execute at most one handler" but you can also use other methods to run for a duration etc.
Here's my working code:
#include <boost/process.hpp>
#include <iostream>
using namespace boost;
namespace {
// declare exit handler function
void _exitHandler(boost::system::error_code err, int rc) {
std::cout << "DEBUG async exit error code: "
<< err << " rc: " << rc <<std::endl;
}
}
int main() {
// create the io_context
asio::io_context ioctx;
// call async_system
process::async_system(ioctx, _exitHandler, "ls /usr/local/bin");
std::cout << "just called 'ls /usr/local/bin', async" << std::endl;
int breakout = 0; // safety for weirdness
do {
std::cout << " - checking to see if it stopped..." << std::endl;
if (ioctx.stopped()) {
std::cout << " * it stopped!" << std::endl;
break;
} else {
std::cout << " + calling io_context.run_one()..." << std::endl;
ioctx.run_one();
}
++breakout;
} while (breakout < 1000);
return 0;
}
The only thing my example lacks is how to use boost::asio::async_result to capture the result - the samples I've see (including here on slashdot) still don't make much sense to me, but hopefully this much is helpful.
Here's the output of the above on my system:
just called 'ls /usr/local/bin', async
- checking to see if it stopped...
+ calling io_context.run_one()...
- checking to see if it stopped...
+ calling io_context.run_one()...
VBoxAutostart easy_install pybot
VBoxBalloonCtrl easy_install-2.7 pyi-archive_viewer
((omitted - a bunch more files from the ls -l command))
DEBUG async exit error code: system:0 rc: 0
- checking to see if it stopped...
* it stopped!
Program ended with exit code: 0
This is the test case
#include <boost/coroutine2/all.hpp>
#include <iostream>
#include <cassert>
int main() {
auto sum = 0;
using Coroutine_t = boost::coroutines2::coroutine<int>::push_type;
auto coro = Coroutine_t{[&](auto& yield) {
for (;;) {
auto val = yield.get();
std::cout << "Currently " << val << std::endl;
sum += val;
yield(); // jump back to starting context
}
}};
std::cout << "Transferring 1" << std::endl;
coro(1); // transfer {1} to coroutine-function
std::cout << "Transferring 2" << std::endl;
coro(2); // transfer {1} to coroutine-function
// assert(sum == 3);
}
For some reason the assert at the end fails with the value of sum being 14 I installed boost (version 1.63) context with the command
./bootstrap.sh --prefix=build --with-libraries=context
./b2 --prefix=build --with-context
I am running this on a MacOS 10.12.6. The compile command was
g++ -std=c++14 -O3 -I boost co.cpp boost/stage/lib/libboost_*.a
Where boost is the boost folder downloaded from sourceforge.
The output of the above test case strangely without the assert is this
Transferring 1
Currently 0
Transferring 2
Currently 2
Currently 2
Why is the first line printed in the coroutine Currently 0? Also why is Currently 2 is printed twice here?? The latter can be seen here as well https://wandbox.org/permlink/zEL9fGT5MrzWGgQB
For the second question it seems like after the main thread has finished, control is transferred back to the coroutine one last time. Why is that? That seems strange..
UPDATE : For the second question, it seems to be different in boost 1.65??!? https://wandbox.org/permlink/JQa9Wq1jp8kB49Up
output of your app with boost-1.65.1 is:
Transferring 1
Currently 1
Transferring 2
Currently 2
probably your problem was caused by bug that has been fixed in boost-1.63