第375期:一扇門的 Bug
最離奇的軟件 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 期,
評論(0)
暫無評論,來搶第一條。