使用自定义比较器对std :: list :: sort进行分段错误?

时间:2017-10-09 03:48:46

标签: c++ sorting segmentation-fault stdlist

在某些代码中,我有一个包含PlayerObject

类型对象的链表
std::list<PlayerObject> unknownPlayers;

我需要根据某些属性对对象进行排序,所以我使用了类

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();
      }
};

通过

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

但由于某种原因,该计划正在接收SEGV。我使用-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

在我看来,比较器可以用于严格弱序。那么在std :: list :: sort?

中出现分段错误的其他可能原因是什么?

编辑1:

我尝试在排序前使用unknownPlayerslist::iterator转换list::reverse_iterator并且工作正常。我甚至可以通过posCount()方法访问值,并且返回的值没有任何奇怪的内容。

编辑2:

我一直试图选择相关的代码发布,但我发现它有点麻烦。 我认为关于unknownPlayers的一些相关事实将是:

  1. std::list::splice方法填充:

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

  2. new_unknown_players也由splice填充。基本上在每个游戏周期中都有关于被看见球员的新信息,这些球员可能被识别为队友,对手或根本没有被识别(未知球员)。尝试通过接近阈值将未识别的玩家与先前识别的玩家(队友或对手)进行匹配,如果失败,则将他们拼接到new_unknown_players链接列表中。

      如果我在上面的代码行中调用splice之前尝试对unknownPlayers进行排序,
    1. sort也会以同样的方式崩溃

    2. 但是sortunknownPlayers为空时不会崩溃(感谢上帝不是那么搞砸了)并且在第一次实际splice之后添加新对象并使其第一次不为空。

    3. 也许这意味着代码的其他部分会破坏列表?我仍然无法理解为什么转换是好的。

      这部分代码:

      //////////////////////////////////////////////////////////////////
      // 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
      

1 个答案:

答案 0 :(得分:0)

嗯,事情是我自己最终解决了这个问题。

显然,这是大量错误的附带影响。当我说巨大时,我的意思是数十个。未定义的行为是屁股的真正痛苦。

像Valgrind这样的消毒杀菌剂和软件无法正确识别哪些代码有时会破坏堆栈内存,这是很可惜的。在这种情况下,sort函数只是访问已经损坏的链表。不知道如果有更精确/详细的工具。

无论如何,谢谢大家。