欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ycsm宕机、bug记录

程序员文章站 2022-05-18 18:36:03
...

1、__stack_chk_fail宕机

  • 今天云海服务器发生了宕机,堆栈如下:
    #0 0xf77a4440 in __kernel_vsyscall ()
    #1 0xf74af687 in raise () from /lib/i386-linux-gnu/libc.so.6
    #2 0xf74b2ab3 in abort () from /lib/i386-linux-gnu/libc.so.6
    #3 0xf74e9fd3 in ?? () from /lib/i386-linux-gnu/libc.so.6
    #4 0xf757f03b in __fortify_fail () from /lib/i386-linux-gnu/libc.so.6
    #5 0xf757efca in __stack_chk_fail () from /lib/i386-linux-gnu/libc.so.6
    #6 0x08212e51 in CGMActivitySys::OnRelevancePhone (this=0xe22f9e0, player=…, phoneNum=0x12c85ab4 “19907316909”, cdKey=0x1525e54c “446244”)
    at game_sys/gm_activity/gs_gm_activity.cpp:4572
    #7 0x0821275f in CGMActivitySys::OnC2S_RelevancePhone (this=0xe22f9e0, player=…, request=0xfff0bee8, errMsg=…)
    at game_sys/gm_activity/gs_gm_activity.cpp:4477
    #8 0x08356672 in MgrGameWorld::OnReceiveProtoEvent (this=0xce2e5f4, player=0x14fd9f10, eventID=CtmGame::C2SG_RELEVANCE_PHONE, request=0xfff0bee8,
    response=0xfff0bf14) at game_sys/base/game_world.cpp:222
    #9 0x085aa79f in PlayingGameProcessor::OnReceiveMsg (this=0x11954030, pClient=0x14eede78, eventID=2434, request=0xfff0bee8, response=0xfff0bf14)
    at login_sys/impl/login_processor/PlayingGameProcessor.cpp:198
    #10 0x0854aed2 in NetManagerListenForGate::OnReceiveMSG (this=0xb605638, pSession=0x14eede78, gameSysID=0 ‘\000’, packet=0x1195902c)
    at net_sys/gate/gate_server.cpp:532

查了一下__stack_chk_fail ()的说明,访问链接:__stack_chk_fail ()
查看链接后,证实代码确实有数组越界了,分析上下文,最终发现是一处拼接url的地方,写数组越界。
源码:

char url[128];
sprintf(url,gsCfg->PhoneURL,gsCfg->gameName,oid_s,phoneNum,act_s);

这里拼接的字符串超出128字节了,原因是随着项目的运行,增开的服务器越来越多,终于有一天,开到了sstx100,原先sstx99不会越界,但是gameName为sstx100时,拼接后长度正好129,越界。

2、宕机ycsm宕机、bug记录

  • 记一次外网验收服务器的core文件分析,堆栈信息如下:
    Program terminated with signal SIGABRT, Aborted.
    #0 0xf76e7440 in __kernel_vsyscall ()
    (gdb) bt
    #0 0xf76e7440 in __kernel_vsyscall ()
    #1 0xf73f2687 in raise () from /lib/i386-linux-gnu/libc.so.6
    #2 0xf73f5ab3 in abort () from /lib/i386-linux-gnu/libc.so.6
    #3 0xf742cfd3 in ?? () from /lib/i386-linux-gnu/libc.so.6
    #4 0xf74374ca in ?? () from /lib/i386-linux-gnu/libc.so.6
    #5 0xf74382d9 in ?? () from /lib/i386-linux-gnu/libc.so.6
    #6 0x085f8d17 in operator delete (pointer=0xd9be110) at main.cpp:48
    #7 0x080aa545 in CFriendSystem::OnPlayerDestroy (this=0xee47370, player=0xd2b6ce0) at game_sys/friend/gs_friend.cpp:1043
    #8 0x088ff60a in EvEventBroadcastImp::ProcessEventArgPtr (this=0xbeef088, ev=0x97cc220 <_ZL17EV_PLAYER_DESTROY>, data=0xffafeb20) at ev_event_broadcast_imp.cpp:239
    #9 0x088ff7a8 in EvEventBroadcastImp::ProcessEventArgs (this=0xbeef088, ev=0x97cc220 <_ZL17EV_PLAYER_DESTROY>, iNumArgs=1) at ev_event_broadcast_imp.cpp:470
    #10 0x0892d107 in EvEventBroadcast::SendEvent (this=0xbeef088, ev=0x97cc220 <_ZL17EV_PLAYER_DESTROY>, a1=…) at ev_event.cpp:153
    #11 0x085b8d2b in CPlayer::OnBeforeOffline (this=0xd2b6ce0) at player_sys/impl/player_sys.cpp:775
    #12 0x085be0fe in CPlayerMgr::RemoveOnlinePlayer (this=0xc3188a8, aaa@qq.com: 2314902248876802048) at player_sys/impl/player_sys.cpp:1842
    #13 0x085c0d30 in CMessageExtenedHandler::on_handle_msg<(unsigned short)207> (pClient=0xd465b80, pPacket=0xc07e2a4) at player_sys/impl/player_sys.cpp:2485
    #14 0x085a7e78 in NetManagerListenForGame::_Handle (this=0xa5f5298, conn=0xccb9fa0, ProtoID=207, packet=0xc07e2a4) at net_sys/game/game_server.h:17
    #15 0x080a413d in CCLNetSocketServer::_baseOnConnectionReceive (this=0xa5f5298, sess=0xccb9fa0, ProtoID=207, packet=0xc07e2a4)
    at …/common_engine/common/net/api/cl_net_socket_server.h:128
    #16 0x088798eb in CCLNetSocketServerBase::__lambda0::operator() (__closure=0xc926d70, conn=0xd465b80, packet=0xc07e2a4) at common/net/cl_net_socket_server.cpp:182
    #17 0x08879fc7 in std::_Function_handler<void(EV_NetClient*, EvMemPacket*), CCLNetSocketServerBase::OnReceive(EV_NetServer*, EV_NetClient*, EvMemPacket*)::__lambda0>::_M_invoke(const std::_Any_data &, EV_NetClient , EvMemPacket ) (__functor=…, __args#0=0xd465b80, __args#1=0xc07e2a4) at /usr/include/c++/4.8/functional:2071
    #18 0x0887e9e8 in std::function<void (EV_NetClient
    , EvMemPacket
    )>::operator()(EV_NetClient*, EvMemPacket*) const (this=0xffafef1c, __args#0=0xd465b80, __args#1=0xc07e2a4)
    at /usr/include/c++/4.8/functional:2471
    #19 0x0887e988 in cl_net_proxy::rcv(EV_NetClient*, EvMemPacket&, std::function<void (EV_NetClient*, EvMemPacket*)>) (this=0xdf19850, pClient=0xd465b80, pkt=…, rcv_cb=…)
    at common/net/net_packet/cl_net_proxy.cpp:73
    #20 0x08879a2b in CCLNetSocketServerBase::OnReceive (this=0xa5f5298, server=0xc07e248, conn=0xd465b80, packet=0xc07e2a4) at common/net/cl_net_socket_server.cpp:187

  • 1、堆栈第#6行,提示的是delete指针的时候,导致发生了coredown;这里是项目重载了delete操作符,用来做内存统计的。

  • 2、看到报错信息是:Program terminated with signal SIGABRT, Aborted.,猜测是delete了一个非法指针。一开始怀疑是double kill,delete了两次。但是进入#7行,分析指针的数据看上去并没有野掉,所以应该是第一次delete。

  • 3、所以再怀疑是内存被踩越界了,导致了非法指针。项目有几十万行代码,最讨厌的就是找内存越界,要老命啊!所幸运气好,这里再往上追踪,是玩家离线的时候,抛出事件EV_PLAYER_DESTROY来销毁每个系统挂载的玩家数据。那么一般情况下,可以认为是上一个游戏系统非法操作,破坏了内存,导致下一个系统再使用内存的时候,挂逼了。然后再去分析游戏log文件,找到上一个系统gs_yunshi,该系统新开发的玩法,并且和QA确认了下,宕机时间点,外网验收正好有人在测试该玩法。嗯,好像找到一个重点嫌疑犯了。

  • 4、然后就是去review该系统的代码,果然发现有这么一段代码:

auto iter = _info_map.find(act_id);
iter->second.act_id = act_id;
iter->second.act_time = nowtime;

这里iter如果等于_info_map.end()的话,那么2、3行的写数据行为,就极有可能破坏内存,把后面的内存写坏了。这段代码是在活动开启的时候触发的,接下来就是模拟操作,然后复现一下coredown文件;按操作成功复现了core文件。然后再修改这段代码,再同样模拟操作,没宕。好了,可以收拾东西回家睡觉了。
这里记一下查内存越界的思路:

  • 1、一般都是因为上文非法操作了内存,导致下文的内存可能被写坏了,所以可以先把上文列为重点嫌疑对象。
  • 2、分析下core文件和日志信息,定位到关键操作(玩家下线了、玩家参与了某个活动等等)或关键函数。
  • 3、有嫌疑对象、关键信息以后,还没有查到结果,那就review代码,分析的时候不要心急,因为它宕了就一定会留下痕迹,所以总能找到蛛丝马迹。
  • 4、定位问题以后,就模拟操作,重现宕机。
  • 5、改正代码,再模拟操作,确认不会发生宕机。

3、记一次恶心BUG的查询

  • 1、策划把炼狱挑战转移到封魔录中,所以需要在玩家登陆的时候,做一次老数据的转换。将外网玩家的炼狱挑战的进度映射到封魔录中。
  • 2、假设封魔录进度有6关,如果封魔录没有通过 6关,那么在在主界面会显示封魔录的按钮,如果6关都通关了,那么主界面隐藏封魔录按钮。
  • 3、由于玩家已经完成炼狱挑战的6关,那么转换到封魔录,对应的进度,也应该是6关都通过了,那么主界面应该隐藏封魔录。

出现bug情况是:有个玩家通关了炼狱6关,但是在主界面出现了封魔录的按钮。当时不知道原因是什么,怕玩家可以再打一次炼狱挑战,拿6个关卡的奖励,于是通宵查了一晚上,分析了所有代码,最终还是一无所获。困惑了一晚上,后来灵光一闪,用延迟工具设置了网络延迟,终于复现了bug。

  • 最终的原因是:服务器的数据发包晚了,客户端在没有完全收到服务器数据的时候,就去初始化主钮界面的封魔录按钮;并且服务器的数据包在随后下发到客户端时,由于客户端界面已经初始化完成,未根据服务器数据再刷新一下界面,丢弃了本次服务器的数据,最终导致BUG。
相关标签: 项目笔记