Possible bug in karma
Stephan Menzel <[email protected]> Wed, 19 Dec 2018 08:46:34 +0100
| Newsgroups | gmane.comp.parsers.spirit.general |
|---|---|
| Message-ID | <CAEQ568sigD1_tPEBFtD9iUFVqa2YSbsBSNO=zTLuE8GdfABekw@mail.gmail.com> |
Hello all,
after unexpected lengthy debug sessions I think I may have discovered a bug
in Karma that apparently came in with 1.68, possibly 1.67. It affects code
that has been running fine for years now as part of a server protocol.
It is a unnecessarily fancy generator for an error-or-OK line out of a
simple struct like this:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
/* describes content of the line */
struct ok_line {
bool result;
std::string message;
std::uint64_t size;
};
BOOST_FUSION_ADAPT_STRUCT(
ok_line,
(bool, result)
(std::string, message)
(std::uint64_t, size)
)
namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;
template <typename OutputIterator>
struct ok_line_generator : karma::grammar<OutputIterator, ok_line()> {
ok_line_generator() : ok_line_generator::base_type(start, "ok line") {
using karma::ulong_long;
using karma::string;
using karma::lit;
using karma::_1;
using karma::_val;
using karma::eps;
error_msg = lit("ERR ") << string << lit("\r\n");
ok_msg = lit("OK ") << ulong_long << lit("\r\n");
start = (eps(phx::at_c<0>(_val) == true) << ok_msg[_1 =
phx::at_c<2>(_val)])
| eps(phx::at_c<0>(_val) == false) << error_msg[_1 =
phx::at_c<1>(_val)];
}
karma::rule<OutputIterator, std::string()> error_msg;
karma::rule<OutputIterator, std::uint64_t()> ok_msg;
karma::rule<OutputIterator, ok_line()> start;
};
What this is supposed to do is, look at the member 'result' in the OK line
struct and, if true, say OK plus a number and if false, say "ERR" plus a
message and CRLF.
I use it in a function like this (example):
std::string generate_ok_line(const std::uint64_t n_size) {
ok_line res;
res.result = true;
res.size = n_size;
ok_line_generator<std::back_insert_iterator<std::string> > g;
std::string ret;
ret.reserve(16);
std::back_insert_iterator<std::string> sink(ret);
const bool result = karma::generate(sink, g, res);
return ret;
}
Now the strange thing is, when I run this with optimization on (Windows,
x64, MSVC141) it works correctly in ~99% of the cases. But not 100. It is
also covered by a unit test, which I never have seen fail (optimized or not
optimized).
BOOST_CHECK_NO_THROW(line = generate_ok_line(2453452465346));
BOOST_CHECK(line == "OK 2453452465346\r\n");
Yet when I run this in the actual non-optimized server (built in the same
solution with the same parameters, statically linked) it will produce
something like this:
"O 235\r"
Always. The numbers vary but there's always only one 'O' and the '\n' is
missing at the end. It never produces correct results in a Debug build when
used within the server application. Which leads me to believe this might be
some initialization / memory error.
Again, this run fine for years in the same environment, Debug or Release.
Unfortunately I cannot say for sure when the error came in as I normally do
all boost upgrades as they come out and rely on the unit tests to report
problems. This one went undiscovered for a possibly long time as this code
doesn't run in Debug too often anymore.
I'm quite puzzled because of that and even though I can easily go for a
simpler approach to save the day, I thought it might still be of interest
for this list.
Cheers,
Stephan
_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general