You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 12:02:22