Boost Spirit示例解析代码带-O3优化崩溃,无优化正常运行求助
Boost Spirit解析代码优化编译后段错误问题
问题说明
编写了一段基于Boost Spirit的字符串解析代码,用于解析竖线(|)分隔的字符串,要求字符串不能包含|、!、(、)、*字符。
编译运行差异
无优化编译正常
编译命令:g++ -std=c++14 -I ${INC} -o ex.out ex.cpp其中
INC指向boost/1.77.0/include,运行输出:./ex.out ABC ----------------------------------------- processing string: "ABC" <str_rule> <try>ABC</try> <success></success> <attributes>[]</attributes> </str_rule> ABC: parse succeeded:带优化编译触发段错误
编译命令:g++ -std=c++14 -I ${INC} -O3 -g -o ex.out ex.cpp运行输出:
./ex.out ABC ----------------------------------------- processing string: "ABC" Segmentation fault (core dumped)测试过g++ 5.2、g++ 12.2,Boost 1.53、1.77.0等版本,问题均存在。
示例代码
//#define BOOST_SPIRIT_DEBUG #include <boost/spirit/home/qi/char/char.hpp> #include <boost/algorithm/string.hpp> #include <boost/spirit/include/qi_symbols.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/variant/recursive_wrapper.hpp> #include <boost/lexical_cast.hpp> #include <string> namespace qi = boost::spirit::qi; namespace phx = boost::phoenix; template <typename It, typename Skipper = qi::space_type> struct parser : qi::grammar<It, Skipper> { parser() : parser::base_type(str_rule) { using namespace qi; auto const str = *(char_ - '|' - '!' - '(' - ')' - '*') ; str_rule = (str % char_('|')); BOOST_SPIRIT_DEBUG_NODE( str_rule ); } private: qi::rule<It, std::string(), Skipper> str; qi::rule<It, Skipper> str_rule; }; int main(int argc, const char*argv[] ) { if( argc != 2 ) { std::cerr << "Usage: main.out <str rule>\n"; return -1; } std::string r = argv[1]; std::cout << "-----------------------------------------" << std::endl; std::cout << "processing string: " << "\"" << r << "\"" << std::endl; typedef std::string::const_iterator It; It f(r.begin()), l(r.end()); parser<It> p; try { bool ok = qi::phrase_parse(f,l,p ,qi::space); if (ok && f == l ) { std::cout << r << ": parse succeeded: \n"; } else { std::cout << r << " failed to parse \n"; } } catch (const qi::expectation_failure<It>& e) { std::cerr << "expectation_failure at '" << std::string(e.first, e.last) << "'\n"; } return 0; }
GDB回溯信息
#0 0x0000000000401f29 in function_base (this=0x7ffda94834c8) at /data/tools/boost/1.77.0/include/boost/function/function_base.hpp:603 603 function_base() : vtable(0) { } Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.x86_64 (gdb) where #0 0x0000000000401f29 in function_base (this=0x7ffda94834c8) at /data/tools/boost/1.77.0/include/boost/function/function_base.hpp:603 #1 function4 (this=0x7ffda94834c8) at /data/tools/boost/1.77.0/include/boost/function/function_template.hpp:706 #2 function (this=0x7ffda94834c8) at /data/tools/boost/1.77.0/include/boost/function/function_template.hpp:1076 #3 rule (name="", this=0x7ffda94834a0) at /data/tools/boost/1.77.0/include/boost/spirit/home/qi/nonterminal/rule.hpp:168 #4 parser<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l> >::parser (this=0x7ffda9483430) at ex.cpp:20 #5 0x000000000040122f in main (argc=<optimized out>, argv=<optimized out>) at ex.cpp:48
问题原因与修复
原因
代码中使用auto const str = *(char_ - ...)创建了一个临时的Boost Proto表达式对象,随后将str % char_('|')赋值给成员变量str_rule。Boost Spirit的rule对象内部存储的是表达式的引用而非拷贝,当构造函数执行完毕后,临时的str对象被销毁,str_rule就持有了悬空引用,触发未定义行为。无优化编译时,临时对象的内存可能未被立即覆盖,所以问题未显现;开启优化后,编译器的内存布局或生命周期优化暴露了这个悬空引用问题,导致段错误。
修复方案
直接将表达式赋值给成员变量str,避免使用临时对象:
parser() : parser::base_type(str_rule) { using namespace qi; // 直接初始化成员变量str,而非创建临时对象 str = *(char_ - '|' - '!' - '(' - ')' - '*'); str_rule = str % char_('|'); BOOST_SPIRIT_DEBUG_NODE(str_rule); }
这样str作为成员变量,生命周期与parser对象一致,str_rule引用的是有效的对象,不会出现悬空引用问题。
内容的提问来源于stack exchange,提问作者user1671556
相关产品推荐
相关产品推荐

