【问题标题】:Segmentation fault in std function std::_Rb_tree_rebalance_for_erase ()std 函数 std::_Rb_tree_rebalance_for_erase () 中的分段错误
【发布时间】:2010-05-19 20:34:32
【问题描述】:

(任何未来的读者请注意:毫无疑问,错误在我的代码中,而不是 std::_Rb_tree_rebalance_for_erase () )

我对编程有点陌生,不确定如何处理似乎来自 std 函数的分段错误。我希望我在做一些愚蠢的事情(即滥用容器),因为我不知道如何解决它。

准确的误差是

程序收到信号EXC_BAD_ACCESS,无法访问内存。
原因:KERN_INVALID_ADDRESS 地址:0x000000000000000c
0x00007fff8062b144 在 std::_Rb_tree_rebalance_for_erase ()
(gdb) 回溯
#0 0x00007fff8062b144 在 std::_Rb_tree_rebalance_for_erase ()
#1 0x000000010000e593 in Simulation::runEpidSim (this=0x7fff5fbfcb20) at stl_tree.h:1263
#2 0x0000000100016078 in main() at main.cpp:43

在分段错误更新两个容器的内容之前成功退出的函数。一个是boost::unordered_multimap,称为carriage;它包含一个或多个struct Infection 对象。另一个容器的类型为std::multiset< Event, std::less< Event > > EventPQ,称为ce

void Host::recover( int s, double recoverTime, EventPQ & ce ) {

  // Clearing all serotypes in carriage
  // and their associated recovery events in ce
  // and then updating susceptibility to each serotype
  double oldRecTime;
  int z;
  for ( InfectionMap::iterator itr = carriage.begin(); itr != carriage.end(); itr++ ) {
    z = itr->first;
    oldRecTime = (itr->second).recT;
    EventPQ::iterator epqItr = ce.find( Event(oldRecTime) );
    assert( epqItr != ce.end() );
    ce.erase( epqItr );
    immune[ z ]++; 
  }
  carriage.clear();
  calcSusc(); // a function that edits an array 
  cout << "Done with sync_recovery event." << endl;
}

最后一行cout &lt;&lt; 出现在段错误之前。

到目前为止,我的想法是在此函数之后立即在 ce 上尝试重新平衡,但我不确定重新平衡为什么会失败。


更新

当我删除 ce.erase( epqItr ); 时,我已经确认 seg 错误消失了(尽管程序随后由于其他原因立即崩溃)。我能够在代码的另一个位置成功删除事件;我在那里用来擦除ce 中的项目的代码与这里的代码相同

回溯没有优化(感谢,bdk)揭示了更多信息:

程序收到信号EXC_BAD_ACCESS,无法访问内存。
原因:KERN_INVALID_ADDRESS 地址:0x000000000000000c
0x00007fff8062b144 在 std::_Rb_tree_rebalance_for_erase ()
(gdb) 回溯
#0 0x00007fff8062b144 在 std::_Rb_tree_rebalance_for_erase ()
#1 0x00000001000053d2 in std::_Rb_tree, std::less, > std::allocator >::erase (this=0x7fff5fbfdfe8, __position={_M_node = 0x10107cb50}) at > stl_tree.h:1263
#2 0x0000000100005417 in std::multiset, std::allocator >::erase (this=0x7fff5fbfdfe8, __position={_M_node = 0x10107cb50}) at stl_multiset.h:346 #3 0x000000010000ba71 in Simulation::runEpidSim (this=0x7fff5fbfcb40) at Simulation.cpp:426
#4 0x000000010001fb31 in main() at main.cpp:43

除非 Xcode 读取行号错误,否则我硬盘中唯一的 stl_tree.h 在第 1263 行是空白的。

有几个人要求查看调用recover的函数。有点复杂:

struct updateRecovery{
updateRecovery( int s, double t, EventPQ & ce ) : s_(s), t_(t), ce_(ce) {}
  void operator() (boost::shared_ptr<Host> ptr ) {
   ptr->recover( s_, t_, ce_ );
  }
private:
  int s_;
  double t_;
  EventPQ & ce_;
};

// allHosts is a boost::multiindex container of boost::shared_ptr< Host > 
// currentEvents is the EventPQ container
// it is an iterator to a specific member of allHosts
allHosts.modify( it, updateRecovery( s, t, currentEvents ) );
cout << "done with recovery" << endl;

最后一个cout 打印出来。该代码以前在没有此特定版本的恢复功能的情况下工作。

Noah Roberts 正确指出问题出在 Simulation.cpp 的第 426 行。跳转到下面的尴尬解决方案。

【问题讨论】:

  • 我的硬盘中唯一出现的 stl_tree.h(也是我的 HD 上唯一包含“_Rb_tree_rebalance_for_erase”的文件)是第 1263 行的 blank(?!)。我在 i686-apple-darwin10 上使用 gcc 4.2.1(Apple build 5646)。 rebalance_for_erase 函数在第 299-429 行定义。
  • 如果您在调用 Host::recover 之后立即在调用代码中添加一个 cout,会打印出来吗?此外,尝试在所有优化和内联关闭的情况下进行编译,您可能会获得更有用的堆栈跟踪
  • 您确定断言已启用吗?也许尝试抛出异常。还要检查免疫阵列是否没有被覆盖过去的边界
  • 这可能是由于代码的任何其他部分碰巧写在其内存之外。也许你可以试试像 Memcheck 这样的内存检查器:valgrind.org/docs/manual/mc-manual.html
  • "Simulation::runEpidSim (this=0x7fff5fbfcb40) at Simulation.cpp:426" 听起来您上面粘贴的代码不是问题代码。您之前粘贴的错误类似,但说它在其他地方:“#1 0x000000010000e593 in Simulation::runEpidSim (this=0x7fff5fbfcb20) at stl_tree.h:1263”Simulation::runEpidSim 看起来像什么,Simulation.cpp:426 有什么?

标签: c++ segmentation-fault std


【解决方案1】:

您可能在调用恢复过程中持有一个指向ce 的迭代器。如果恢复碰巧删除了该项目,则迭代器将失效,并且将来的任何使用(例如尝试擦除它)都可能导致段错误。

如果我们能看到更多关于在恢复调用之前和之后如何使用 ce 的上下文,这将有所帮助。

【讨论】:

  • 你是对的! (我需要研究如何以及何时发生树重新平衡。)
【解决方案2】:

问题是在 Simulation.cpp 的第 426 行,我试图删除 EventPQ currentEvents(又名ce)容器中的一个事件,我的 recover() 函数刚刚删除了该事件。迭代器显然已失效。哑巴。

课程:

  • 调试未优化的代码
  • 密切关注非标准相关框架的含义

为了未来:在 valgrind 中跟踪内存

我仍然不明白为什么调试器将我提到 stl_tree.h 中一个明显的空白行。

在这里,我非常感谢帮助我度过难关的人们。我将修改我的问题,以便对任何未来的读者更简洁。

【讨论】:

  • 这是您遇到崩溃时应遵循的一般规则。从上到下查看调用堆栈,直到您找到自己的代码并开始查看。通常,您会发现该错误是在您自己的代码中的堆栈跟踪中的某处引起的,而不是库中的。如果不是这种情况,您通常会发现您在半小时前遇到了 UB,而现在却遇到了任何原因。我实际上从未遇到过库错误。遇到很多编译器错误,但我想不出任何库错误。
【解决方案3】:

也许对assert 的调用未与您的配置一起编译。生产代码中的断言通常是一个坏主意[TM]。

您也可能超出immune 的界限。

试试:

    if (epqItr != ce.end()) 
    {
        ce.erase(epqItr);
        if (z is within immune's bounds)
        {
            ++immune[z]; 
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-23
    • 2013-09-16
    • 1970-01-01
    • 2015-09-11
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多