std 函数 std::_Rb_tree_rebalance_for_erase () 中的分段错误

发布于 2024-09-02 07:36:01 字数 3356 浏览 1 评论 0原文

(请注意任何未来的读者:不出所料,错误出现在我的代码中,而不是 std::_Rb_tree_rebalance_for_erase () )

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

精确的误差是

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

在分段错误更新两个容器的内容之前成功退出的函数。一种是名为 carriageboost::unordered_multimap;它包含一个或多个struct Infection 对象。另一个容器的类型为 std::multiset<事件,std::less<活动> > 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 << 行出现在段错误之前。

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


更新

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

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

程序收到信号EXC_BAD_ACCESS,无法访问内存。
原因:KERN_INVALID_ADDRESS,地址:0x000000000000000c
std::_Rb_tree_rebalance_for_erase () 中的 0x00007fff8062b144
(gdb) 回溯
std::_Rb_tree_rebalance_for_erase () 中的 #0 0x00007fff8062b144
#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 在Simulation::runEpidSim (this=0x7fff5fbfcb40) 在Simulation.cpp:426
#4 0x000000010001fb31 在 main() 处 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 打印。该代码以前可以在没有此特定版本的恢复功能的情况下工作。

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

(Note to any future readers: The error, unsurprisingly, is in my code and not std::_Rb_tree_rebalance_for_erase () )

I'm somewhat new to programming and am unsure how to deal with a segmentation fault that appears to be coming from a std function. I hope I'm doing something stupid (i.e., misusing a container), because I have no idea how to fix it.

The precise error is

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x000000000000000c
0x00007fff8062b144 in std::_Rb_tree_rebalance_for_erase ()
(gdb) backtrace
#0 0x00007fff8062b144 in 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

The function that exits successfully just before the segmentation fault updates the contents of two containers. One is a boost::unordered_multimap called carriage; it contains one or more struct Infection objects. The other container is of type std::multiset< Event, std::less< Event > > EventPQ called 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;
}

The last cout << line appears immediately before the seg fault.

My idea so far is that the rebalancing is being attempted on ce immediately after this function, but I am unsure why the rebalancing would be failing.


Update

I've confirmed the seg fault goes away (though the program then immediately crashes for other reasons) when I remove ce.erase( epqItr );. I am able to remove events successfully in another place in the code; the code I use there to erase items in ce is identical to what's here.

Backtracing without optimization (thanks, bdk) reveals much more information:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x000000000000000c
0x00007fff8062b144 in std::_Rb_tree_rebalance_for_erase ()
(gdb) backtrace
#0 0x00007fff8062b144 in 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

Unless Xcode is reading line numbers wrong, the only stl_tree.h in my hard drive is blank on line 1263.

A few people asked to see the function that calls recover. It's a bit complicated:

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;

The last cout prints. The code worked before without this particular version of the recovery function.

Noah Roberts correctly pointed out that the problem is at Simulation.cpp, line 426. Jump below for embarrassing solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

超可爱的懒熊 2024-09-09 07:36:01

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

如果我们能够了解更多有关在调用恢复之前和之后如何使用 ce 的上下文,将会有所帮助。

Possibly you're holding onto an iterator into ce across the call to recover. If recover happens to remove that item the iterator will be invalidated and any future use (say an attempt to erase it) could result in a seg fault.

It would help if we could see more context of how ce is used before and after the call to recover.

回忆凄美了谁 2024-09-09 07:36:01

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

经验教训:

  • 对尚未优化的代码进行调试
  • 密切注意非 std 相关帧的含义

对于未来:在 valgrind 中跟踪内存

我仍然很困惑为什么调试器将我推荐给stl_tree.h 中显然是空白行。

我非常感谢那些帮助我解决这个问题的人。我将修改我的问题,以便对未来的读者来说更加简洁。

The problem was that on line 426 of Simulation.cpp, I tried to delete an event in the EventPQ currentEvents (a.k.a. ce) container that my recover() function had just deleted. The iterator had obviously been invalidated. Dumb.

Lessons:

  • Debug on code that has not been optimized
  • Pay close attention to what the non-std related frames imply

And for the future: Trace memory in valgrind

I'm still stumped why the debugger referred me to an apparently blank line in stl_tree.h.

I've massive appreciation here for the people who have helped me work through this. I'm going to revise my question so it's more concise for any future readers.

烟凡古楼 2024-09-09 07:36:01

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

您也可能超出了免疫的界限。

尝试:

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

Perhaps the call to assert is not compiled with your configuration. Assertions in production code are usually a Bad Idea[TM].

You could also be exceeding immune's boundaries.

Try:

    if (epqItr != ce.end()) 
    {
        ce.erase(epqItr);
        if (z is within immune's bounds)
        {
            ++immune[z]; 
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文