Poketto

一年多一天,全世界的 Zune 一起罢工:微软的官方修复是「等明天」

目录

文章主题概念插画

配图:AI 生成的概念示意图,非真实现场、产品截图或研究数据。

TL;DR:2008 年 12 月 31 日,大批 30GB 的第一代 Zune 在同一天开机卡死。原因是时钟驱动里把「天数换算成年份」的循环,在闰年的第 366 天永远出不去。微软给的办法是让电池耗尽,等元旦过了再充电开机;设备到第二天会自己好。

发生在什么时候

2008 年 12 月 31 日,这一年是闰年,这一天是第 366 天。当天凌晨前后,不少第一代 Zune 30(30GB 版)卡在启动画面,怎么按都没反应。因为是同一天、同一款机器、全球同时出事,网上很快有了「Y2K9」的戏称。

一个循环,吃掉了一整天

Zune 的实时时钟存的不是年月日,而是「自 1980 年 1 月 1 日起过了多少天」。要显示日期,驱动就得把天数换算成年份:一年一年往外减,平年减 365,闰年减 366。

据当时流传的代码分析(出自发现者在 ZuneBoards 上的帖子,Make 杂志转载,并非微软官方事后报告),闰年那一支写的是「剩余天数大于 366 才减」。到了 12 月 31 日,剩余天数恰好等于 366:条件不成立,没减;又因为是闰年,也走不到「年份加一」的出口。循环原地打转,设备便停在开机画面,看上去像死机,其实是在拼命空转。

这类 bug 很典型:边界条件差一位(「大于」本该是「大于等于」),平时完全不暴露,一年只有一天会触发,还偏偏发生在闰年。

官方方案:等

微软的说法是,问题出在时钟驱动,这个驱动来自 Freescale,只用于 Zune 30,所以其他型号不受影响。给用户的办法很朴素:让电池自然耗尽,然后在格林尼治时间 1 月 1 日中午之后充电开机。日期一过,天数不再是 366,循环自然跳出,机器恢复正常。

换句话说,这个 bug 的「补丁」是日历。微软同时表示会发布修复,避免下一个闰年(2012)重演。

值得记住的

  • 时间相关代码的边界条件,要用「正好卡在边界」的值去测,比如闰年最后一天。
  • 一年才触发一次的 bug,测试几乎一定抓不到,只能靠评审和对日期逻辑格外多疑。
  • 硬件厂商的第三方驱动出问题,用户并不关心是谁写的;承担后果的是贴着品牌的那一方。

来源:

关注这个空间,它的新文章会出现在你的关注动态里。