4

I develop my code in my spare time. Preferably in debug mode. Recently, when I tried to build release version, then I got the error (runtime, output: 1\n2\n then failure). I located the piece of code (below), which contains the error, and I found, that the error only occurs, when optimization level is -Os, -Ofast, -O2, -O3 but not -O, -O0, -O1, -Og. In release mode I am constrained in debug abilities. What is the cause of the error? What is the method to find such errors?

#!/usr/bin/env bash -vex WARN="-W -Wall -Wextra" INCLUDE="-isystem /c/libs/boost-trunk" OPT="-O2" g++ -x c++ - -std=gnu++1y $INCLUDE

$WARN $OPT -o a <<__EOF && ./a && echo -e "\e[1;32msucceeded\e[0m" || echo -e "\e[1;31mfailed\e[0m"

#include <iterator>
#include <string>
#include <iostream>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>

using namespace boost::spirit;

template< typename Iterator >
struct skipper
        : qi::grammar< Iterator >
{

    skipper();

private :

    typename skipper::base_type::start_type skipper_;

};

template< typename Iterator >
skipper< Iterator >::skipper()
    : skipper::base_type(skipper_, "skipper") 
{
    std::cerr << 1 << std::endl;
    auto const ana =
            *~qi::char_('*') > +qi::char_('*')
            ;
    std::cerr << 2 << std::endl;
    skipper_ =
            qi::space
            | ("/*" > ana > *(~qi::char_("/*") > ana) > '/')
            | ("//" > *(qi::char_ - qi::eol) > (qi::eol | qi::eoi))
            ; // R"(\s+|(\/\*[^*]*\*+([^/*][^*]*\*+)*\/)|(\/\/[^\r\n]*))"
    std::cerr << 3 << std::endl;
}

using input_type = std::string;
using input_iterator_type = std::istreambuf_iterator< typename input_type::value_type >;
using base_iterator_type = multi_pass< input_iterator_type >;

template struct skipper< base_iterator_type >;

using skipper_type = skipper< base_iterator_type >;

int main()
{
    skipper_type const skipper_;
    std::cerr << 4 << std::endl;
    return EXIT_SUCCESS;
}
__EOF

gcc -v 2>&1 | tail -n1:

gcc version 4.8.1 (rev5, Built by MinGW-W64 project) 
Heyji
  • 1,113
  • 8
  • 26
Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169
  • I use valgrind to do these issues. `valgrind --db-attach=yes` is most helpful (on linux, of course). However, my setup is broken so I just inspected the code in an editor this time :/ – sehe Dec 24 '13 at 21:28

1 Answers1

4

It's a bug in your code, nothing wrong with the compiler or the optimization levels.

The cinch is with expression templates (like the ones used by Boost Proto, and hence by Boost Spirit). They are only valid to the end of their enclosing full expression [1]

The canonical workaound is:

 BOOST_SPIRIT_AUTO(ana, *~qi::char_('*') > +qi::char_('*'));

You can find it here: http://svn.boost.org/svn/boost/trunk/libs/spirit/example/qi/typeof.cpp and it got first introduced in the comments at this blog post: http://boost-spirit.com/home/articles/qi-example/zero-to-60-mph-in-2-seconds/

The explicit fix I tested (which worked nicely on my box, no warnings remaining in valgrind):

auto const ana = boost::proto::deep_copy(
        *~qi::char_('*') > +qi::char_('*'))
        ;

Spirit X3 promises to remove this wart. Slightly related, I think Protox11 also removes this issue by being aware of references at all times.


[1] Grep the standard for lifetime extension of temporaries. The expression templates keep references to the literals used (the rest has value semantics anyways), but the temporaries aren't bound to (const) references. So they go out of scope. Undefined Behaviour results

sehe
  • 374,641
  • 47
  • 450
  • 633
  • With respect to the footnote: why an optimization affect the existence of the error? – Tomilov Anatoliy Dec 25 '13 at 02:48
  • It doesn't! It's just undefined behaviour and it happened to /appear to work/ only. This is why valgrind/purify etc are so important. – sehe Dec 25 '13 at 11:17
  • Linux users are lucky because they have at their disposal such free tool as valgrind. – Tomilov Anatoliy Dec 25 '13 at 16:01
  • Which is why all my projects are cross-platform, even if the customer isn't. If need be, I'd suggest my employer to buy the proper tools :) – sehe Dec 25 '13 at 16:15
  • 2
    In **boost trunk** (probably it should be at http://www.boost.org/libs/spirit/example/qi/typeof.cpp in next version) I found `boost::spirit::qi::copy` from `#include `, that solve the problem too. – Tomilov Anatoliy Dec 25 '13 at 16:24
  • Nice addition, @Dukales – sehe Dec 25 '13 at 16:25
  • 1
    *Not from specified header. My mistake, sorry. But exist anyways. – Tomilov Anatoliy Dec 25 '13 at 16:26
  • what to do with `auto const distinct_word = boost::spirit::repository::distinct(qi::alnum | '_');` local variables, where `boost::spirit::repository::distinct` from `#include `? I cannot make it as part of the grammar class, because I don't know required type of result expression, so I use `auto` to automatically deduce type, and therefore `distinct` is a local variable, used in rules definitions. – Tomilov Anatoliy Dec 28 '13 at 16:28
  • Just use `qi::rule` like everyone else :) If you don't know the required type you can find out using something like `struct {} _ = distinct(qi::alnum | '_')` which will tell you the type. You might want to [look at Spirit X3](http://boost-spirit.com/home/2013/02/23/spirit-x3-on-github/) which has a more lightweight style that you seem to prefer. However, it's not released yet. – sehe Dec 28 '13 at 16:42
  • I found name by means of using `abi::__cxa_demangle` from `` and keyword `decltype()` and `typeid().name()`, but it is too long, and therefore does not fit here. – Tomilov Anatoliy Dec 28 '13 at 16:55
  • In any case, it does not matter. Which parameters should I set to `qi::rule`? – Tomilov Anatoliy Dec 28 '13 at 16:57
  • Oh well, that trick is not needed if you read your compiler's message. Also, just `std::cout << typeid(x).name()` and pipe the output through c++filt would do :) – sehe Dec 28 '13 at 16:57
  • @Dukales on the "which parameters" question, it depends on the context, obviously. Why don't you open a new question with the actual problem so we can answer that? – sehe Dec 28 '13 at 16:58
  • Ok. I open the new question. – Tomilov Anatoliy Dec 28 '13 at 16:59
  • @Dukales I just noticed your [deleted question](http://stackoverflow.com/questions/20817592/grammar-behaviour-depends-on-debug-release-mode). You probably realized I don't have access to that BB repo. I hope you find the time to reduce to a SSCCE that you can include and (re)open that question? Good luck – sehe Dec 29 '13 at 00:26
  • what is SSCCE? You have an answer to that question? Does it make sense to open the question and BB repo again? I found that you hint about `repository::distinct(qi::copy(qi::alnum | '_'))` is usefull and is a solution of the problem. – Tomilov Anatoliy Dec 29 '13 at 05:34
  • @Dukales I can't know whether I have an answer, because the question doesn't include the relevant source. This is what http://sscce.org means. I'd be wary of "solving" things this way unless you have very good tool-verification in place. So, you decide whether you'd like to reopen the question :/ – sehe Dec 29 '13 at 13:04
  • Don't worry, I already solve that issue. I conclude, that no one part of the grammar should be the local. – Tomilov Anatoliy Dec 29 '13 at 16:34