Какая техника отладки для генератора кармы с ошибкой во время выполнения

Нелегко определить, в чем заключается мой вопрос программирования, так как я не понимаю, в чем проблема. Действительно, у меня есть ошибка времени выполнения, потерянная где-то в Библиотеке кармы бодрости духа. Я полагаю, что мне здесь не хватает техники отладки.

Я видел, что макрос BOOST_SPIRIT_DEBUG_NODE(S) очень помогает парсерам, хотя я не нашел ссылки на него в руководстве. Для генераторов, кажется, это не работает, и у меня (честно) не хватает смелости (я должен?) Копаться в коде этой библиотеки, чтобы понять, где проблема.

Я попытался сгенерировать три типа моей единой структуры в грамматике без каких-либо проблем. Поэтому я предполагаю, что ошибка происходит из-за преобразования структуры U в вариант boost, опять же (см. Атрибут Casting для boost::variable), но у меня нет никаких доказательств.

Для тех, кто может решить эту проблему с помощью простой проверки кода, вот минимальный пример моей проблемы:

#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>

//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/karma.hpp>
#include <boost/variant/variant.hpp>

namespace ka = boost::spirit::karma;

typedef std::back_insert_iterator<std::string> iterator;
typedef enum {A, B, C } E;
typedef enum {FOO, BAR, POINTER } K;

struct U /* Union like */
{
    K kind;
    double foo;
    E bar;
    unsigned int * p;
};

class EName : public ka::symbols<E, std::string>
{
public:
    EName()
    {
        add (A,"A") (B,"B") (C,"C");
    }
};

typedef boost::variant<E, double, unsigned int *> UVariant;

namespace boost { namespace spirit { namespace traits {
    template<>
    struct transform_attribute<const U,UVariant,ka::domain>
    {
        typedef UVariant type;
        static type pre(const U & u) {
            switch (u.kind)
            {
            case FOO:
                return type(u.foo);
            case BAR:
                return type(u.bar);
            case POINTER:
                return type(u.p);
            }
            return type(A);
        }
    };
}}}

class grm: public ka::grammar<iterator, U()>
{
public:
    grm():grm::base_type(start)
    {
        start = ka::attr_cast<UVariant >(bar | foo | pointer);
        bar = b;
        foo = ka::double_;
        pointer = ka::hex;
    }
private:
    ka::rule<iterator,U()> start;
    ka::rule<iterator,double()> foo;
    ka::rule<iterator,E()> bar;
    ka::rule<iterator,unsigned int *()> pointer;
    EName b;
};

int main(int argc, char * argv[])
{
    grm g;
    U u;
    //unsigned int a;
    u.kind = BAR;
    //u.foo = 1.0;
    u.bar = B;
    //u.p = &a;

    std::string generated;
    std::back_insert_iterator<std::string> sink(generated);
    ka::generate(sink,g,u);
    std::cout << generated;

    return 0;
}

ОБНОВЛЕНИЕ: Компилятор: Visual C++ Express версии 11 и 12. Стек вызовов останавливается на:

            // If you are seeing a compilation error here stating that the
            // third parameter can't be converted to a karma::reference
            // then you are probably trying to use a rule or a grammar with
            // an incompatible delimiter type.
            if (f(sink, context, delim)) // <--- call stack stops here (last boost spirit reference)

Также я обнаружил, что определение макроса _SCL_SECURE_NO_WARNINGS затеняет следующее предупреждение компилятора:

предупреждение C4996: 'std::_Copy_impl': вызов функции с параметрами, которые могут быть небезопасными - этот вызов полагается на вызывающую программу для проверки правильности переданных значений. Чтобы отключить это предупреждение, используйте -D_SCL_SECURE_NO_WARNINGS. См. Документацию о том, как использовать Visual C++ "Проверенные итераторы".

Это предупреждение относится к нескольким файлам boost-spirit:

  • дух \ главная \ карма \ подробно \output_iterator.hpp(242)
    дух \ главная \ карма \ подробно \output_iterator.hpp(577)
    дух \ главная \ карма \ подробно \output_iterator.hpp(574)
    дух \ главная \ карма \ подробно \alternative_function.hpp(170)
    дух \ главная \ карма \ подробно \alternative_function.hpp(162)
    дух \ главная \ карма \ оператор \alternative.hpp(122)
    дух \ главная \ карма \ вспомогательный \attr_cast.hpp(85)
    дух \ главная \ карма \ нетерминал \ подробно \generator_binder.hpp(43)
    дух \ главная \ карма \ нетерминал \ подробно \generator_binder.hpp(52)
    дух \ главная \ карма \ нетерминал \rule.hpp(193)
    дух \ главная \ карма \ нетерминал \rule.hpp(230)

1 ответ

Решение

Я не могу воспроизвести ошибку.

Я не могу "решить" это из небольшой проверки кода. Однако я могу сделать две вещи:

  • Я могу подтвердить, что макросы отладки не реализованы для Karma

  • Я могу выйти на конечности и сказать, что, возможно, bar|foo|pointer должен быть глубоко скопирован:

    start = ka::attr_cast<UVariant >(boost::proto::deep_copy(bar | foo | pointer));
    

Я пробовал с включенным UB-sanitizer и Address-sanitizer, но они оба не сообщали о каких-либо проблемах.


ОБНОВЛЕНИЕ На самом деле, похоже, что я могу "решить" это после небольшой проверки кода (и счастливого мозгового волнения) в конце концов:

На самом деле, работа под valgrind действительно показывает проблему, и действительно, она исчезает при добавлении deep_copy,

Я добавлю несколько ссылок на то, как я выдвинул гипотезу этих вещей:

Другие вопросы по тегам