1

Not easy to sate what my programming question is as I don't really see where the problem is. Indeed, I have a runtime error lost somewhere in the boost spirit karma Library. I guess I miss a debugging technique here.

I have seen that the macro BOOST_SPIRIT_DEBUG_NODE(S) greatly helps for parsers, although I couldn't find any reference to it in the manual. For generators, it seems this is not working and I (honestly) don't have the courage (should I ?) to dig into the code of this library to understand where the issue is.

I have tried to generate the three types of my union-like structure alone in a grammar without any issue. So I assume the error comes from the cast of the U structure into a boost variant, again (see Casting attribute to boost::variant) but I have no proof.

For those who could solve it with a simple code inspection, here is the minimal example of my issue:

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

UPDATE: Compiler: Visual C++ Express version 11 and 12. The call stack stops at :

            // 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)

Also I have found out that the definition of the _SCL_SECURE_NO_WARNINGS macro shadowed the following compiler warning:

warning C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'

This warning referring to several boost-spirit files:

  • spirit\home\karma\detail\output_iterator.hpp(242)
    spirit\home\karma\detail\output_iterator.hpp(577) 
    spirit\home\karma\detail\output_iterator.hpp(574) 
    spirit\home\karma\detail\alternative_function.hpp(170)
    spirit\home\karma\detail\alternative_function.hpp(162) 
    spirit\home\karma\operator\alternative.hpp(122)
    spirit\home\karma\auxiliary\attr_cast.hpp(85)
    spirit\home\karma\nonterminal\detail\generator_binder.hpp(43)
    spirit\home\karma\nonterminal\detail\generator_binder.hpp(52)
    spirit\home\karma\nonterminal\rule.hpp(193)
    spirit\home\karma\nonterminal\rule.hpp(230)
Community
  • 1
  • 1
Heyji
  • 1,113
  • 8
  • 26
  • "I have a runtime error" - what is it? I can't reproduce that. Debugging technique #1 is to observe the available facts. – sehe Jul 11 '16 at 20:25
  • I think I just got a lucky brain wave, see my answer – sehe Jul 11 '16 at 20:50

1 Answers1

1

I can't reproduce the error.

I can't "solve it" from a little code inspection either. I can however do two things:

  • I can confirm that debug macros don't appear to be implemented for Karma

  • I can go out on a limb and say that perhaps bar|foo|pointer needs to be deep-copied:

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

I tried with UB-sanitizer and Address-sanitizer enabled, but they both didn't report any problems.


UPDATE In fact it looks like I can "solve" it from a little code inspection (and lucky brainwave) after all:

In fact, running under valgrind DOES show a problem and indeed, it goes away when adding the deep_copy.

I'll add some references as to how I hypothesized these things:

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Live demo: [Live On Coliru](http://coliru.stacked-crooked.com/a/ab18b21d259da5df) – sehe Jul 11 '16 at 20:57
  • It does solve the runtime error, but not the warning (see my updates) which is quite "scary" (?). I will read your references tomorrow and report if something is still unclear. – Heyji Jul 11 '16 at 21:37
  • Thanks for adding a little bit of information on the actual symptoms to your question. That makes it a lot easier to help you. – sehe Jul 11 '16 at 22:14
  • That warning is not at all scary (although it's a [nice pun](http://stackoverflow.com/q/14391705/85371) to make!). There's a lot of online references about it (google it). If you read it well, it just says "the programmer must have checked the iterators". You can bet the Spirit devs have done so, but the warnings are _very hard_ to avoid in the generic case (without actually using that compiler define, obviously) – sehe Jul 11 '16 at 22:16