Ошибка сегментации с тривиальной грамматикой Spirit Parser

Я сталкиваюсь с частыми segfaults с моим парсером Spirit Qi.

Потратив несколько дней на отладку проблемы (я обнаружил, что трассировку стека невозможно найти), я решил сократить ее до минимального примера. Может ли кто-нибудь сказать, что я делаю неправильно, если что?

Сохраните код как bug.cpp, скомпилируйте с помощью g++ -Wall -o bug bug.cpp, и все готово.

//#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;
}

Я тестировал это с

  • g++ 4.4, 4.5, 4.6 и
  • версии boost 1.42 (ubuntu meerkat) и 1.46.1.1 (natty)

Выход

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

Или, с повышением 1.46.1, он сообщит Spirit version: 2042


person sehe    schedule 14.05.2011    source источник
comment
Вы объявляете и инициализируете story перед the; почему вы ожидаете, что это сработает? Попробуйте rule<Iterator, Skipper> the, story;.   -  person ildjarn    schedule 14.05.2011
comment
Ага. Я написал и упорядочил объявления и инициализации в обоих порядках в моем реальном коде, но каким-то образом я, должно быть, ошибся в одном, что привело меня к (ошибочному) выводу, что это не причина. Завтра подтвердится, была ли решена вся проблема, спасибо   -  person sehe    schedule 14.05.2011


Ответы (1)


Изменение порядка инициализации, как вы предложили в своем ответе, просто скрывает проблему. Настоящая проблема заключается в том, что rule<> имеют правильную семантику копирования C++. Вы можете исправить это, переписав инициализацию грамматики следующим образом:

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

Обоснование и более подробное объяснение см. здесь.

person hkaiser    schedule 14.05.2011
comment
Спасибо за внимание. Две вещи: я думаю, что этот пункт часто задаваемых вопросов не совсем ясен. Это политика, что если вы вызываете конструктор чистой копии для существующего lvalue, вы должны использовать .alias(), всегда? Другой: есть ли способ получить полезную информацию из трассировки стека, как это сделал я? Как это бывает, все это гораздо менее интуитивно понятно, чем, скажем, flex или Coco/R, и когда что-то идет не так, я чувствую себя «с завязанными глазами» из-за огромной сложности окружающей логики шаблона. Мне очень нравится Spitit, но я начинаю уставать от поиска/решения ошибок. - person sehe; 15.05.2011