您的位置:首页 > 其它

记录一则线上bug

2017-03-07 20:41 113 查看
最近线上出现一次崩溃事故,core在了dynamic_cast类型转化上面,之前一直跑的好好的,第一反应是存在野指针了。

void RoomHandler::KickAllPlayersInRoom(Room* room)
{
vector<IPlayer*> players = room->GetPlayers();
for (size_t i=0; i<players.size(); i++) {
ProcessPlayerQuit(dynamic_cast<Player*>(players[i]), room);
}
}


经过仔细排查并没有发现释放完后,没有在容器中删除的情况。

其中的GetPlayers大概是这种结构:

std::vector<IPlayer*>  Room::GetPlayers()
{
std::vector<IPlayer*> v;
for( PlayerContainer::iterator it = _players.begin(); it != _players.end(); ++it){
v.push_back( it->second );
}
return v;
}


_players是一种map类型,上面的函数实际上就是把map中的数据复制一份到vector中,现在要做的很显然就是把_players打印出来,嗯,标准的gdb并不能打印出来需要的(值,数据)信息,下面的是红黑树中的一些基本元素,要解析出来可以试着强制转换才能打印。

(gdb) print room._players
$8 = {
_M_t = {
_M_impl = {
<std::allocator<std::_Rb_tree_node<std::pair<unsigned int const, IPlayer*> > >> = {
<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<unsigned int const, IPlayer*> > >> = {<No data fields>}, <No data fields>},
members of std::_Rb_tree<unsigned int, std::pair<unsigned int const, IPlayer*>, std::_Select1st<std::pair<unsigned int const, IPlayer*> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, IPlayer*> > >::_Rb_tree_impl<std::less<unsigned int>, false>:
_M_key_compare = {
<std::binary_function<unsigned int, unsigned int, bool>> = {<No data fields>}, <No data fields>},
_M_header = {
_M_color = std::_S_red,
_M_parent = 0x0,
_M_left = 0x954e7d0,
_M_right = 0x954e7d0
},
_M_node_count = 0
}
}
}


有工具是可以直接打印stl的,需要去下载一个文件,可以去参考一下http://blog.csdn.net/luoleicn/article/details/5968038

然后我们就可以打印map中的东西了:

(gdb) pmap room._players <int>          //只考虑第一个元素
Map size = 0


让人惊讶的蛋疼的事情发生了,Map的空的!

难道多线程下被其他线程改写了?可实际上我们的游戏主逻辑是单线程的,所有的数据库线程读取都是使用回调的。然后又去仔细研究了一下回调,目前的的回调是在epoll的主循环中处理的,这里会处理所有已完成的数据库操作的队列。所以实际上还是在一个线程中完成的。

顺序执行感觉根本不该出现这种情况,在这种束手无策的情况下,只能一句句代码开始分析,找了一两个小时终于发现问题的根源出现在ProcessPlayerQuit上,这个函数调用的层次非常的深,这个函数会清除room中player信息,并且处理一些玩家在不在房间或者不在游戏的情况,在其中某一个分支上竟然会再次调用到KickAllPlayersInRoom。

在循环之初就已经清除掉了room._players之中的元素,第二轮调用到的时候dynamic_cast尝试解引用一个已经删除的元素就core掉了。

现在的问题就有点像下面这种情况。

vector<IPlayer*> players = room->GetPlayers();   //从 room._players获取玩家
for (size_t i=0; i<players.size(); i++) {
//某一个分支会出现
//第二次到这的时候room._players就已经清空掉了。
for (size_t j =0; j<players.size(); j++) {
//room._players.erase(uid);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bug 指针