3

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

ildjarn
  • 62,044
  • 9
  • 127
  • 211
sehe
  • 374,641
  • 47
  • 450
  • 633
  • You're declaring and initializing `story` before `the`; why would you expect this to work? Try `rule the, story;`. – ildjarn May 14 '11 at 01:29
  • Yup. I had spelled and ordered the declarations and initializations in both orders in my actual code, but somehow I must have gotten one wrong, leading me to (wrongly) conclude that it was _not_ the cause. Will confirm tomorrow whether the whole problem was solved, thx – sehe May 14 '11 at 01:31

1 Answers1

5

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.

hkaiser
  • 11,403
  • 1
  • 30
  • 35
  • Thx for the heads up. Two things: I think that FAQ item is not abundantly clear. Is it a policy that if you invoke the pure copy constructor on an existing lvalue you should use .alias(), **always**? The other is: is there a way to get useful information out of a stack trace like I got? As it happens, this is all a lot less intuitive than, say, flex or Coco/R and when something is awry I feel as though 'blindfolded' due to the immense complexity of the surrounding template logic. I like Spitit a lot, but I'm starting to feel weary of the impact bug-finding/solving – sehe May 14 '11 at 20:03