游戏中一个奇怪的崩溃问题

        前两天晚上加班,发完版本,放到线上测试服,丢给QA测试。伸了个懒腰,刚准备起来走走,倒个水、上个厕所什么的,只听QA Leader喊道:“老刘,版本有问题,客户端刚进入服务器就崩溃!”

        我擦咧,什么状况?我赶紧放下水杯,坐回位置上,打开测试服上的版本,挂上vs;等待客户端初始化完毕,登录,准备进入游戏世界,刚读条完毕,崩了……必崩!还好及时发现。

        调试器捕获到异常,停了下来,查看堆栈,是特效初始化的地方,莫名奇妙,这地方以前从来没崩过。再看异常类型,内存读取违例,0xC0000005,真是老朋友了……仔细查看后,发现是一个指针的值为0x0000000a,指针是FX::FX_Composite::sm_pkLuaState, sm_pkLuaState是FX_Composite的类静态变量,用于读取特效文件(特效文件是用lua格式书写的),崩溃点就是sm_pkLuaState->DoFile。可是sm_pkLuaState被显示初始化为NULL,并且当第一次进到FX_Composite的构造函数中时,会判断sm_pkLuaState如果为NULL,则new一个出来, 这里怎么会变成0x0000000a呢?奇怪奇怪。

        既然可以稳定重新,那咱就放心了。在FX_Composite:: FX_Composite()中下断点,判断sm_pkLuaState为NULL的地方,重开客户端。客户端初始化、登录、读条进入游戏世界,读条完毕,断点断下来了,查看sm_pkLuaState的值,已经为0x0000000a了,因此if (sm_pkLuaState == NULL)判断失败,直接跳过了下面的sm_pkLuaState= new LuaState();等到调用sm_pkLuaState->DoFile的时候,直接崩了,指针为0x0000000a不崩才怪!

        可是前面说过,“sm_pkLuaState是类静态变量,被显示初始化为NULL” ,为什么会变成一个非零值呢?这个嘛,肯定是被人改了啊啊啊啊啊啊啊。唔,既然是被人改了,让我们来找出元凶,哼哼。再次重开客户端,挂上vs,先暂停进程,在watch窗口输入&FX::FX_Composite::sm_pkLuaState,取出这个指针的地址,显示为0x133a2d0c,下一个数据断点,输入0x133a2d0c,然后继续运行客户端,当指针值被改变的时候,调试器就能捕获到。客户端初始化、登录、读条进入游戏世界,读条完毕,bang,调试器弹出对话框,捕捉到指针被改啦,点击确定后,查看代码,竟然是这样:


这是什么鬼?这玩意儿跟FX::FX_Composite八竿子打不着啊。可调试器不会错,应该就是这里,待我镇定下来,看看ms_iWorkingQueueItemOrderID是什么东西。


 额,也是个类静态变量。哎怎么会怎么会,这静态变量咋改写到另一个静态了?我脑子还没转过来。沉思了一会儿,还没想通,这时站我旁边的大伟哥说道:“应该是数组越界了吧?”

        哎呦妈呀,大伟哥一语惊醒梦中人啊,赶紧查看地址:


这两变量挨的好近啊,0x133a2d0c – 0x133a2cec = 0x20,才32个字节啊,再看BL_AsyncOperation::LS_END,是个枚举值,为8,没错,4 * 8 =32。


数组定义貌似没啥问题啊,继续看m_eOpType,等于OT_PATH,为9,果然越界了,正好改到指针的值。可是既然数组长度为8,这9又是从哪里来的呢?查看m_eOpType定义,也是个枚举值。


而且这枚举值跟数组定义用的枚举值不是同一个类型!!!LS_END属于enum LoadState,OT_PATH属于enum OperationType,怎么会这样……谁干的啊?赶紧打开svn blame这个文件,发现……这个数组从一开始就是这么定义的,没人改过……瞬间感觉好无力,以前咋一直没崩呢。

         到现在为止,问题的原因定位到了,就是数组下标m_eOpType用的值域与定义数组长度的值域不相同。那到底是定义数组长度用错了值,还是m_eOpType类型错误呢?仔细查看上下文后发现,m_eOpType定义没错,是数组长度定义用错了枚举值,应该写成这样:



再看这两个枚举,终于明白以前为啥不崩了。项目刚开始的时候,那时候还没有OT_PATH、OT_VIDEO、OT_RELOAD_CONFIG,因此OT_END=8,LS_END=8,所以即使用错枚举值,两个长度一样,也不会崩,后来逐渐加了OT_PATH等3个枚举值,导致OT_END=11,与LS_END不一致了,这种情况下,崩溃是正常的。不过这只能解释项目刚开始的时候不崩的原因,不能解释OT_PATH等枚举值逐渐加入以后为何一直没崩,OT_PATH加入也有一年多的时间了,OT_END与LS_END早就不一致了,按理说早就该崩啦;猜测原因可能有二:

1.      内网开发版本,这两个静态变量的间隔可能不止0x20,中间可能还有padding字符,因此即使越界,也不会导致指针被改写

2.      外网发布版本,这回编译器凑巧将这两个变量紧挨着排列,同时,刚进入游戏时,触发了m_eOpType=OT_PATH的逻辑,就崩了,大概是这样吧……

 

将数组定义修改后重新编译,运行,一切OK。感谢大伟哥!




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值