当前位置: 华文星空 > 知识

Bug往事(2)

2016-05-15知识

继续说那些奇葩的Bug。

靠不住的系统组件:Vista和Speech Recogition

我们游戏使用了语音识别,使用了DirectX里面的XAudio来采集声音。Windows Vista里面有一个语音识别的组件,启动那个程序,然后玩我们的游戏,玩了一段时间,因为没有使用麦克风,那个程序会自动关闭使用麦克风,然后我们的游戏就Crash了。又是一个跨进程的奇葩Bug。

从现场来看,Crash在使用XAudio的库代码里面。看不出什么线索,最后发现在日志里面,Crash前一会儿,XAudio的dll被Unload掉了。Vista那个语音组件很强悍,也会跨进程追杀大法,在自己进程把我的进程dll给Unload掉了。

虽然遇事先要怀疑自己的代码有问题,但这个情况太匪夷所思,所以我试图推卸责任,我跑了几个其他DirectX程序和Demo,但凡用到XAudio组件的,在Vista Speech Recognition这一大招前无一幸免,全部Crash。

问题不在我们这里,但是作为一个职业杀虫人,我有着「只解沙场为国死,何须bug裹尸还」的觉悟,决定还是要想办法搞定它。

我猜这个组件退出的时候,广播了点什么消息,让系统所有进程去卸载这个Dll。我找了一个微软提供的库Detours Express,专做Hook API的勾当。它会反汇编API的入口代码,然后动态替换入口,插入jmp指令去执行我们自己的函数。先看了文档,搞懂这个东西怎么用,然后猜测是一个OS内部的消息导致Unload DLL,我们就拦截了RegisterWindowMessage。一通翻箱倒柜,啥有意义的东西都没发现。

再用spy++来拦截消息,发现有一个MSUIM.msg.rpcsendreceive的消息面目狰狞,很可疑。就在收到这个消息以后,Dll就被Unload了。于是我们用Detours截住这个消息,直接返回。

以为搞定了,但结果还是不行,有几条别的消息也会触发Unload Dll,我一一用Detours拦截返回。拦截的消息越来越多,看来不是个解决办法。于是我怀疑我们没有拦截到正确的消息,怀疑OS启动的时候便注册了一堆内部用的消息,而不是在运行进程的时候才注册。那些消息里肯定有我想要的,我便异想天开地Hook了User32.dll,拦截下所有消息,在安全模式下把修改过的user32.dll覆盖原来的文件,然后满怀希望的重启动Vista的时候。结果不出所料的蓝屏了...User32.dll是凡人能随便碰的吗?这不是一个User friendly的库,应该改名叫God32.dll。

这个bug搞了1周,最后才想到最基本的道理,说不定只是Dll内部引用计数被清掉了,所以系统就卸掉Dll了。当Vista语音组件Unload XAudio的时候,系统去看看XAudio库有没有什么别人引用,结果发现居然没有,那就顺手清理了。就像地上有100块钱,你东张西望,发现没有人宣布拥有那张钱,没有一点点犹豫,你随手就把它放进了裤兜,进行了回收。嗯,就是这样的,我喜欢比喻这种修辞手法。

理论上创建XAudio设备的时候没有做什么额外的加Dll引用计数的事情,怀疑是MS的bug,创建D3D设备、DInput设备的时候都不需要做什么特别的事情的,但他们的引用计数都没有问题。

于是我恶搞了一下,在初始化XAudio完成以后,手动做了一次LoadLibrary,把XAudio2_1.dll强行Load一遍,相当于自行增加了引用计数。于是再无Crash。

从此我们的游戏,在Vista 32上过上了幸福的生活。

可得结论:Vista靠不住

Takeaway: 不知道该说什么了,这个bug太奇葩了。

性能的迷思

临近最终版本发布的时候,测试人员发现一个问题,当在Vista上连续打游戏过7关以后,游戏帧数一下子变成原来一半了。大家觉得很诡异,都不相信,之前整天玩游戏都没问题的,于是责令测试人员再重现几次,否则拖出去刨坑埋了。我也没当回事,

< style data-emotion-css="19xugg7"> .css-19xugg7{position:absolute;width:100%;bottom:0;background-image:linear-gradient(to bottom,transparent,#ffffff 50px);} < style data-emotion-css="12cv0pi"> .css-12cv0pi{box-sizing:border-box;margin:0;min-width:0;height:100px;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:absolute;width:100%;bottom:0;background-image:linear-gradient(to bottom,transparent,#ffffff 50px);}
< style data-emotion-css="1pr2waf"> .css-1pr2waf{font-size:15px;color:#09408e;}
编辑于 2016-05-15 21:17
< style data-emotion-css="ch8ocw"> .css-ch8ocw{position:relative;display:inline-block;height:30px;padding:0 12px;font-size:14px;line-height:30px;color:#1772F6;vertical-align:top;border-radius:100px;background:rgba(23,114,246,0.1);}.css-ch8ocw:hover{background-color:rgba(23,114,246,0.15);}
< style data-emotion-css="1xlfegr"> .css-1xlfegr{background:transparent;box-shadow:none;} < style data-emotion-css="1gomreu"> .css-1gomreu{position:relative;display:inline-block;}
Bug