Search code examples
c++boostboost-spiritboost-spirit-qi

Segmentation fault with trivial Spirit Parser grammar


I'm running into frequent segfaults with my Spirit Qi parser.

After spending days to debug the issue (I found the stacktraces impossible to grok) I decided to trim it down to a minimal example. Can anyone tell what I'm doing wrong, if anything?

Save code as bug.cpp, compile with g++ -Wall -o bug bug.cpp and you should be good to go.

//#define BOOST_SPIRIT_DEBUG_PRINT_SOME 80
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/version.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <fstream>
#include <iterator>
#include <string>

namespace /*anon*/
{
    using namespace boost::spirit::qi;

    template <typename Iterator, typename
        Skipper> struct bug_demo : 
            public grammar<Iterator, Skipper>
    {
        bug_demo() : 
            grammar<Iterator, Skipper>(story, "bug"),
            story(the),
            the("the")
        {
//          BOOST_SPIRIT_DEBUG_NODE(story);
//          BOOST_SPIRIT_DEBUG_NODE(the);
        }

        rule<Iterator, Skipper> story, the;
    };

    template <typename It>
        bool do_parse(It begin, It end)
    {
        bug_demo<It, space_type> grammar;
        return phrase_parse(begin, end, grammar, space);
    }
}

int main()
{
    std::cout << "Spirit version: " << std::hex << SPIRIT_VERSION << std::endl;

    try
    {
        std::string contents = "the lazy cow";
        if (do_parse(contents.begin(), contents.end()))
            return 0;
    } catch (std::exception e)
    {
        std::cerr << "exception: " << e.what() << std::endl;
    }
    return 255;
}

I've tested this with

  • g++ 4.4, 4.5, 4.6 and
  • boost versions 1.42 (ubuntu meerkat) and 1.46.1.1 (natty)

The output is

sehe@meerkat:/tmp$ ./bug 
Spirit version: 2020
Segmentation fault

Or, with boost 1.46.1 it will report Spirit version: 2042


Solution

  • Changing the initialization order as you suggested in your answer just hides the problem. The actual problem is, that rule<>'s have proper C++ copy semantics. You can fix this by rewriting your gramar initialization as:

    bug_demo() : 
        grammar<Iterator, Skipper>(story, "bug"),
        story(the.alias()),
        the("the")
    {}
    

    For a rationale and a more detailed explanation, see here.