阅界资讯

第375期:一扇门的 Bug

阅阅界编辑部2阅读4分钟

最离奇的软件 Bug,你听说过哪些?下面这个是我本周看到,绝对可以排进史上前十名。我把它译出来,跟大家分享,以下是第一人称的叙述:2013年,我在 Valve 公司从事游戏开发。当时,第一代虚拟现实 VR 头盔 Oculus DK1 刚刚发售。公司决定为这款头盔移植游戏,让我来移植,搞清楚 VR 的游戏环境。我就选了2004年我们公司开发的《半条命2》来移植。

移植了一个片段后,我们发现实际效果很好,就决定移植整个游戏,并且发布了发售预告。移植过程中,我试玩了很多片段,但没有从头到尾玩一次。等到移植完成,就在发售前夕,我决定完整玩一次,如果发现有什么问题,就写在发布说明里面。我心想,应该不会有大问题,毕竟这个游戏已经发售10年了,无数人玩过,反响良好。但是,万万没有想到,我居然遇到了一个重大 Bug。

游戏的开头部分,玩家来到火车站,一个守卫让你进去一个房间。很奇怪,房间的门是关着的,你进不去,就……卡住了。你没死,就是哪儿也去不了。前面的门关着,你进不去,也退不出去,身后的大门已经关上了。你被困在一个走廊里,旁边有个守卫,无路可走。真是奇怪。游戏的剧情是,你必须进入这个房间,才能往下玩。你又去找守卫,他指着锁着的门,仅此而已,你被困住了。

我上网查了视频,心想自己是不是记错了。没错,门应该是自动打开的,你走进去就行了,但是……现在这扇门却关了!我心想完蛋了,这游戏没法发布了。我赶忙联系了其他人,包括一些十年前参与这个游戏开发的人。他们测试后,都说确实有问题,而且在非 VR 模式下也一样,门也是关着的,所以肯定不是我移植弄坏的。但没人知道原因,因为代码根本没改过。有人甚至追溯到游戏的原始源代码,编译了最初发售时的游戏版本——结果发现,那个原始版本也坏了,门也是关着的。

这怎么可能?大家慌了,这意味着这个 Bug 十年前就存在,但当年编译为什么没出现,十年后重新编译就出现了,这到底什么回事?在花了大约一天时间,重新使用当年的调试和回放工具之后,一位同事弄明白了哪里出了问题。

如果仔细观看游戏,你会发现这扇门有一瞬间,其实自动解锁并打开了,但是房间里还有第二个守卫站在门后。这个守卫站得离门非常近,门打开的一瞬间会轻轻碰到守卫的脚趾,然后又弹回,重新关上,并自动上锁。由于游戏没有考虑怎么处理这种情况并重新打开门,所以游戏就卡住,你无法前进了。一旦弄明白怎么回事,解决方法就很简单。我们把守卫往后移大约一毫米,门就很顺利自动打开了。

现在我们可以发布游戏了。但是,问题还是没有彻底解决。为什么这个游戏当初没有出现这个 Bug,原版里守卫的脚趾也挡着门啊?为什么十年后重新编译,Bug 就出现呢?或者说,Bug 其实一直都在,为什么十年前这扇门没有关上呢?于是,一场旷日持久的漏洞搜寻就此展开。我们终于发现了答案,就是老生常谈的浮点运算。

《半条命2》于2004年发布,当时编译用的是较旧的8087或 x87 数学指令集。这些指令集的浮点数精度五花八门,有些是32位,有些是64位,有些是80位,不同的代码段使用了不同的精度。十年后的2013年,SSE 指令集已经成为所有 x86 CPU 的标准配置,编译器默认使用 SSE,它有明确的精度,根据代码需求使用32位或64位,是可以预测的。

真相就是,十年前编译用了32位精度,现在用了64位,小数点的差异造成了几毫米的误差,让守卫的脚趾碰到了门。好了,现在玩家终于可以走进大门,继续玩下去了。

来源|阮一峰科技爱好者周刊第 375 期,https://github.com/ruanyf/weekly/blob/master/docs/issue-375.md

每周精选周刊头条

评论(0)

暂无评论,来抢第一条。