2010-05-19 262 views
1

(请注意,以任何未来的读者:错误,勿庸置疑,在我的代码,而不是标准:: _ Rb_tree_rebalance_for_erase())故障:: _ 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在仿真:: runEpidSim(这= 0x7fff5fbfcb20)在stl_tree.h:1263
#2 0x0000000100016078在main()在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 <<行出现在seg故障之前。

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


我已经证实了赛格故障更新消失(尽管该程序,然后立即崩溃其他原因),当我删除ce.erase(epqItr);。我能够在代码中的另一个地方成功删除事件;我在那里用于清除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中的std :: _ Rb_tree,标准: :std_tree.h:1263
#2 0x0000000100005417在std :: multiset,std :: allocator>:std :: allocator> :: erase(this = 0x7fff5fbfdfe8,__position = {_ M_node = 0x10107cb50})。在stl_multiset上擦除(this = 0x7fff5fbfdfe8,__position = {_ M_node = 0x10107cb50})。H:346 #3 0x000000010000ba71在仿真:: runEpidSim(此= 0x7fff5fbfcb40)在Simulation.cpp:426
#4 0x000000010001fb31在main.cpp中主要():43

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

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

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打印。该代码之前没有这个特定版本的恢复功能。

诺亚罗伯茨正确地指出,问题出现在Simulation.cpp,第426行。下面跳转到尴尬的解决方案。

+0

什么是stl_tree.h:1263? – 2010-05-19 20:50:32

+0

在我的硬盘(也是我的HD上唯一包含'_Rb_tree_rebalance_for_erase'的文件)中显示的唯一stl_tree.h在行1263(?!)上是*空格*。我在i686-apple-darwin10上使用gcc 4.2.1(Apple build 5646)。 rebalance_for_erase函数在第299-429行定义。 – Sarah 2010-05-19 20:58:24

+1

如果您在调用Host :: recover之后立即在调用代码中添加cout,是否打印出来?另外,尝试编译所有优化和内联关闭,你可能会得到一个更有用的堆栈跟踪 – bdk 2010-05-19 20:59:18

回答

3

可能你在整个调用中持续迭代到ce以恢复。如果恢复发生时删除该项目,则迭代器将失效并且将来的任何使用(例如试图删除它)都可能导致seg错误。

如果我们能够在调用恢复前后看到更多关于ce的使用情况,这将有所帮助。

+0

你是对的! (我需要研究如何以及何时进行树重新平衡。) – Sarah 2010-05-19 21:47:48

0

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

你也可能超过immune的界限。

尝试:

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

的问题是,在Simulation.cpp的426行,我试图删除EventPQ currentEvents(又名ce),我recover()功能刚刚删除了容器的事件。迭代器显然已失效。哑。

教训:

  • 上的代码调试尚未优化
  • 密切注意什么非性病相关的帧意味着

,并为未来:跟踪存储器在valgrind中

我仍然难住为什么调试器将stl_tree.h中的一行显示为空行。

我在这里为那些帮助我完成这项工作的人们大力赞赏。我要修改我的问题,以便将来读者更简洁。

+1

这是碰撞时遇到的一般规则。从顶部看看callstack,直到你找到自己的代码并开始寻找。一般而言,您会发现该错误是在您自己的代码中的堆栈跟踪中发生的,而不是库。如果不是这种情况,你通常会发现你在半小时前击中了UB,并且现在正在遇到任何这种情况。我其实从来没有遇到过一个库bug。遇到很多编译器错误,但我想不出任何库错误。 – 2010-05-19 22:36:17