简体   繁体   English

使用自定义比较器在std :: list :: sort上出现分段错误?

[英]Segmentation Fault on std::list::sort with custom comparator?

In some code I have a linked list with objects of type PlayerObject 在某些代码中,我有一个链接列表,其中包含PlayerObject类型的对象

std::list<PlayerObject> unknownPlayers;

And I need to sort the objects according to some property, so I use the class 我需要根据某些属性对对象进行排序,所以我使用了类

class CountCmp
    : public std::binary_function< PlayerObject, PlayerObject, bool >
{
public:
    result_type operator()( const first_argument_type & lhs,
                            const second_argument_type & rhs ) const
      {
         return lhs.posCount() < rhs.posCount();
      }
};

By 通过

unknownPlayers.sort( PlayerObject::CountCmp() );

But for some reason the program is receiving SEGV. 但是由于某种原因该程序正在接收SEGV。 I used -fsanitize=address compilation flag to investigate and the stack-trace was like: 我使用-fsanitize=address编译标志进行调查,并且堆栈跟踪类似于:

ASAN:SIGSEGV
=================================================================
==8521==ERROR: AddressSanitizer: SEGV on unknown address 0x0003000003e8 (pc 0x7fe7ca6d6540 bp 0x7fff07c51720 sp 0x7fff07c516e8 T0)
#0 0x7fe7ca6d653f in std::__detail::_List_node_base::_M_transfer(std::__detail::_List_node_base*, std::__detail::_List_node_base*) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x9e53f)
#1 0x881e58 in std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >::_M_transfer(std::_List_iterator<rcsc::PlayerObject>, std::_List_iterator<rcsc::PlayerObject>, std::_List_iterator<rcsc::PlayerObject>) /usr/include/c++/5/bits/stl_list.h:1747
#2 0x87f79f in std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >::splice(std::_List_const_iterator<rcsc::PlayerObject>, std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >&&, std::_List_const_iterator<rcsc::PlayerObject>) /usr/include/c++/5/bits/stl_list.h:1444
#3 0x87d22e in std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >::splice(std::_List_const_iterator<rcsc::PlayerObject>, std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >&, std::_List_const_iterator<rcsc::PlayerObject>) /usr/include/c++/5/bits/stl_list.h:1464
#4 0x87d90c in void std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >::sort<rcsc::PlayerObject::CountCmp>(rcsc::PlayerObject::CountCmp) (/home/felipe_coimbra/.../sample_player+0x87d90c)
#5 0x86c3e3 in rcsc::WorldModel::localizePlayers(rcsc::VisualSensor const&) /home/felipe_coimbra/.../world_model.cpp:2412
#6 0x864b37 in rcsc::WorldModel::updateAfterSee(rcsc::VisualSensor const&, rcsc::BodySensor const&, rcsc::ActionEffector const&, rcsc::GameTime const&) /home/felipe_coimbra/.../world_model.cpp:910
#7 0x81a7ac in rcsc::PlayerAgent::Impl::analyzeSee(char const*) /home/felipe_coimbra/.../player_agent.cpp:1552
#8 0x819b52 in rcsc::PlayerAgent::parse(char const*) /home/felipe_coimbra/.../player_agent.cpp:1393
#9 0x816519 in rcsc::PlayerAgent::handleMessage() /home/felipe_coimbra/.../player_agent.cpp:886
#10 0x75b3a8 in rcsc::BasicClient::runOnline(rcsc::SoccerAgent*) /home/felipe_coimbra/.../basic_client.cpp:158
#11 0x75ac9e in rcsc::BasicClient::run(rcsc::SoccerAgent*) /home/felipe_coimbra/.../basic_client.cpp:93
#12 0x5e933e in main /home/felipe_coimbra/.../main_player.cpp:102
#13 0x7fe7c9d6f82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#14 0x5e8ed8 in _start (/home/felipe_coimbra/.../sample_player+0x5e8ed8)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ??:0      std::__detail::_List_node_base::_M_transfer(std::__detail::_List_node_base*, std::__detail::_List_node_base*)
==8521==ABORTING

It seems to me the comparator is ok for strict-weak ordering. 在我看来,比较器可以进行严格的弱订购。 So what would be other possible cause to a segmentation fault in std::list::sort ? 那么,什么可能导致std :: list :: sort中的分段错误呢?

EDIT 1: 编辑1:

I've tried to tranverse unknownPlayers using list::iterator and list::reverse_iterator just before sorting and it works fine. 我试图在排序之前使用list::iteratorlist::reverse_iterator list::iterator unknownPlayers ,并且效果很好。 I could even access values through posCount() method and there wasn't anything odd with the returned values. 我什至可以通过posCount()方法访问值,并且返回的值没有什么奇怪的。

EDIT 2: 编辑2:

I've been trying to pick relevant code to post but I'm finding it a little troublesome. 我一直在尝试选择要发布的相关代码,但发现它有些麻烦。 I think some relevant facts about unknownPlayers would be: 我认为与unknownPlayers有关的一些事实是:

  1. It's filled by std::list::splice method: 它由std::list::splice方法填充:

    unknownPlayers.splice(unknownPlayers.end(), new_unknown_players );

new_unknown_players is also filled by splice . new_unknown_players也由splice填充。 Basically in every game cycle there's new information about seen players and these players may be identified as teammates, opponents or not identified at all(unknown players). 基本上,在每个游戏周期中,都有关于看过的玩家的新信息,这些玩家可能被识别为队友,对手,或者根本未被识别(未知玩家)。 There is a try to match not identified players with previously identified players(teammates or opponents) by a proximity threshold and if this fails, they're spliced into new_unknown_players linked list. 尝试通过接近度阈值将未识别的玩家与先前识别的玩家(队友或对手)进行匹配,如果失败,则将其拼接到new_unknown_players链接列表中。

  1. sort also does crash in the same way if I try to sort unknownPlayers before the call of splice in the line of code above 如果我尝试在上述代码行中的splice调用之前对unknownPlayers进行sort也会以相同的方式崩溃

  2. However, sort does not crash while unknownPlayers is empty (thank god it's not that messed up) and right after the first time the splice actually adds new objects and makes it not-empty for the first time. 但是,在unknownPlayers为空时sort不会崩溃(谢天谢地,这不是搞砸了),并且在第一次splice实际添加新对象并使其第一次不为空。

Maybe this means in some other part of code something is corrupting the list? 也许这意味着在代码的其他部分损坏了列表? I can't still understand why tranversing is ok. 我仍然不明白为什么遍历还可以。

Code of this part: 这部分的代码:

//////////////////////////////////////////////////////////////////
// splice temporary seen players to memory list
// temporary lists are cleared
M_teammates.splice(M_teammates.end(),
                       new_teammates);
M_opponents.splice(M_opponents.end(),
                       new_opponents);
// I've put some debug in this line
M_unknown_players.splice(M_unknown_players.end(),
                             new_unknown_players);
// And here too

/////////////////////////////////////////////////////////////////
    // create team member pointer vector for sort

    PlayerPtrCont all_teammates_ptr;
    PlayerPtrCont all_opponents_ptr;

    {
        const PlayerCont::iterator end = M_teammates.end();
        for (PlayerCont::iterator it = M_teammates.begin();
             it != end;
             ++it) {
            all_teammates_ptr.push_back(&(*it));
        }
    }
    {
        const PlayerCont::iterator end = M_opponents.end();
        for (PlayerCont::iterator it = M_opponents.begin();
             it != end;
             ++it) {
            all_opponents_ptr.push_back(&(*it));
        }
    }

/////////////////////////////////////////////////////////////////
    // sort by accuracy count
    std::sort(all_teammates_ptr.begin(),
              all_teammates_ptr.end(),
              PlayerObject::PtrCountCmp());
    std::sort(all_opponents_ptr.begin(),
              all_opponents_ptr.end(),
              PlayerObject::PtrCountCmp());

// I've put some more debug here
M_unknown_players.sort( PlayerObject::CountCmp() );
// And here

Well, thing is I ended up solving the issue myself. 好吧,我最终自己解决了这个问题。

Apparently that was a collateral effect of a huge collection of bugs. 显然,这是大量错误的附带影响。 And when I say huge I mean dozens. 当我说巨大的时候,我的意思是几十个。 Undefined behavior is a true pain in the ass. 未定义的行为是驴子的真正痛苦。

It's a pitty that sanitizers and softwares like Valgrind are unable to te identify properly what code is corrupting stack memory sometimes. 可怜的是,诸如Valgrind之类的消毒器和软件无法正确识别出哪些代码有时破坏了堆栈内存。 The sort function was just accessing an already corrupted linked list in this case. 在这种情况下,排序功能只是访问已损坏的链表。 Wonder If there's any more precise/detailed tools for this. 想知道是否还有其他更精确/详细的工具。

Anyway, thank you all. 无论如何,谢谢大家。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM