把iPhone日期设置成1970年1月1日,手机会无法启动,从而变成砖,这个问题引起很多人的关注,还有好奇宝宝去尝试,结果……
有一种Bug叫时间Bug,现在,我们来解析下,那些让计算机难以理解的人类的时间计算问题。
20世纪后期,全世界都沉浸在对21世纪的希望和憧憬之中。但是,关注计算机的人们却在为一个问题大伤脑筋,就是计算机系统将2000年当作1900年处理的“Y2KBug”(千年虫)难题。“末日论”拥护者们甚至担心计算机会全体罢工,而人类则走向灭亡。好在人们事先考虑到了这个问题,并做出了应对措施,这才安然无恙地迎来了新千年。
正如在阳光强烈的白昼看不到星光一样,与时间有关的Bug中,Y2KBug太有名了,以至于其他事件在它面前都不足以成为人们茶余饭后的谈资。但事实上,和时间有关的Bug是软件诞生以来最为频发的Bug类型之一。自软件诞生起到现在,仍然不时有此类Bug发生。与时间有关的Bug类型主要有:对闰年现象处理不当导致的Bug、Y2KBug、源于计算机结构的先天性Bug等。
闰年
虽然人们常说1年有365天,但事实上,地球围绕太阳公转一周所用的时间并非365天,严格来说需要365天5小时48分46秒。公历上减去365天后,余下的时间约为4年累计1天,故每4年于2月加1天,变为29天,使当年的长度为366天,该年就为闰年。
但是,规定每4年必须有一闰年的日历是儒略历,其制定者就是说出那句“布鲁图斯,连你也……”名言的罗马的尤利乌斯·恺撒。不过,儒略历随着时间的推移会产生一定误差。而弥补这一缺陷的便是现在大多数国家正在使用的格里高利历,其制定者是教皇格里高利十三世。
儒略历规定4年一闰。也就是说,400年中有100年是闰年,且400年中共增加100天。这种方法虽然可以纠正地球公转引起的偏差,但还不够精确。而弥补了这一点的格里高利历中,400年间,闰年只有97次,比儒略历少了3次。这样人们在时间的计算上就精确多了,但与4年无条件有1次闰年的儒略历相比,它的闰年计算方法更为复杂。
以下是计算闰年的公式:
- 可以被4整除的年份是闰年(2008年、2012年、2016年……)
- 其中能被100整除的年份为平年(2100年、2200年、2300年……)
- 平年中可以被400整除的年份是闰年(1600年、2000年、2400年……)
如果随便问一个路人什么是闰年、如何计算闰年,十个人中有九个会答不上来。因为计算的公式本身比较复杂,而且就算不知道也不会影响自己的日常生活。不知计算机程序员是否也没将这个问题放在眼里,从而忽略了和闰年相关的软件Bug,导致其成为软件Bug界的“常客”。
微软的野心之作与闰年Bug
已经去世的史蒂夫·乔布斯被人们称为“创新符号”和“怪才”,他回归“苹果”公司后取得的首次巨大成功就是便携式媒体播放器(一般称为MP3播放器)——iPod。看到这款产品在世界范围内掀起了一股风潮,而且销量惊人,全世界的家电企业都开始进军便携式MP3播放器市场。在便携式媒体播放器领域从未尝到过甜头的三星公司曾经将便携式MP3播放器领域的管理部门作为子公司分离了出去,在iPod风潮的冲击下,三星公司重新合并了子公司,决定向该领域发起冲击。
软件公司微软也不想错过“这块蛋糕”,推出了名为“Zune”的产品,想要制衡“苹果”公司。
但是,曾通过推出Windows而垄断个人计算机操作系统的微软在iPod面前也败下阵来。祸不单行,美国当地时间2008年12月31日0时起,微软公司30GB 版Zune音乐播放器同时出现了大规模的无法启动故障。微软公司发布声明称:“正在努力解决这个问题,将会通过Zune官方网站尽快公布解决方法。”为控制事态发展,微软可谓大伤脑筋。
其实,原因就出在闰年上。Zune中内置的日期计算软件计算当前日期时,闰年计算出现错误,导致机器无法启动。既然找明了原因,解决起来就容易了。出现故障24小时后,2009年1月1日,日期不同了,年份也变了,Zune也就恢复了正常。
之后,微软到2011年为止又相继推出多款产品,但最终都没能超越iPod。终于,2011年3月,微软宣布停止生产Zune 播放器。
让全世界游戏玩家备受煎熬的PS3闰年Bug
2010年3月1日,日本索尼公司的电视游戏机Play Station3(以下简称PS3)出现了死机现象。出现问题的并非当时最新款的PS3薄版,而是旧版PS3。这个故障使全世界众多玩家一整天都没能玩到游戏。而这天是韩国的公休日(三一节),正是玩游戏的大好时间,所以韩国的玩家们才更倒霉。很多韩国玩家这一天只能对着屏幕上的故障画面发呆、抓狂。
2010年3月1日启动PS3 后,韩国等亚洲国家的时间会变更为2000年1月1日,而美国等北美国家则变为1999年12月31日。而且玩家无法联网,达到一定等级后积累的个人游戏记录和名下的奖品亦告消失,同时屏幕弹出“奖品信息登录失败。游戏结束。(8001050F)”的消息。这个故障也是闰年Bug引起的。到了第二天,3月2日,问题自动解决,机器又恢复正常。
医院系统故障,纸笔代替电脑
1989年9月19日上午,位于宾夕法尼亚州的医疗共享系统(Shared Medical Systems,以下简称SMS)公司的电话铃声此起彼伏。打电话的虽然不是同一个人,但说的话都一样:
“医院系统停止工作了。”
这一天,美国全境一百多家医院不得不放弃之前一直使用的计算机系统,改为用纸笔记账。使用SMS提供的软件和系统的所有医院都出现了这样的情况。SMS技术人员认定这是突发状况,作为权宜之计,他们建议所有医院都关闭计算机,然后开始寻找事故原因。
几小时后,人们查明了原因。SMS开发的软件出现错误,计算机无法识别1989年9月19日这个日期,所以出现故障。那为什么是9月19日呢?原因就在于16位数据结构。当时医院使用的电脑是以1900年1月1日为起点计算日期的。故障发生的1989年9月19日在起点基础上又过了32 768(即215)天,已经超出了16位数据结构可以承受的数字范围0~32 767。因此,计算机无法识别这个数字,系统就出现故障。
这次故障并没有造成数据丢失或者医疗器械停止工作从而危及患者生命的事故,但另一个不能忽视的问题是,今后仍然存在发生此类问题的隐患。尤其是现在大多数服务器都在使用的Unix 操作系统在时间计算上还存在着以下问题:SMS的计算机系统时间起点是1900年1月1日,而Unix是以1970年1月1日为起点计算日期的。Unix在此基础上加上系统时间(秒)计算日期,但问题在于,保存系统时间的数据类型是“32位带符号整数”。
32位带符号整数可以存储-231~231-1的数字,也就是-2 147 483 648 ~2 147 483 647。1970年1月1日0时00分,在UTC的基础上再过2 147 483 647 秒就是2038年1月19日3时14分7秒(UTC)。从这一刻起再过1秒,也就是2038年1月19日3时14分8秒开始,系统存储的时间值不是从2 147 483 647 变为2 147 483 648,而是变为-2 147 483 648。
因为存储时间值的空间只有32位,所以无法存储2 147 483 648 这个数字。这样,从2038年1月19日3时14分8秒(UTC)开始,Unix操作系统会将当前时间计算为1901年12月13日20时45分53秒(UTC)。如果不尽快解决此问题,类似事件将会重演。
解决的方法其实很简单。只要将系统时间从现有的带符号32位整数扩大到64位或者128位即可。当然也不能盲目扩大,因为这涉及与时间改变相关的代码兼容问题。最近开发的64位操作系统中,存储时间的数据类型使用的都是64位带符号数。使用64位带符号数后,可以表示的最后时间是292 277 026 596 年12月4日(约2920亿年)。但与现有代码实现兼容的常规解决方案尚未出现。
罢工的导航仪
2012年3月31日,美国、澳大利亚、英国等地使用的TOMTOM导航仪突然停止工作,屏幕上出现“无法连接到GPS卫星”的消息,此外不显示任何信息。几天后,TOMTOM的生产厂家发布了用于修复的补丁程序。引起这次故障的元凶就是GPS接收器所用的软件。软件出现闰年Bug,使整个导航仪变为无用之物。本来TOMTOM 就在与智能手机内置导航系统(谷歌地图等)的竞争中节节败退,苦不堪言,这次事件让他们又挨了当头一棒。
日常生活中的Y2KBug
1992年的一天,美国的玛丽·班达尔接到了去明尼苏达州威诺纳的幼儿园上学的通知。但是,出生于1888年的玛丽·班达尔在1992年已经104岁了。这是一个典型的Y2KBug。计算机只处理了出生年份四位数中的后两位,以此为标准寻找学龄前儿童,所以才发生了这样的怪事。
布洛杰特101岁时,他的汽车保险费突然上涨了3倍!查明原委后发现,还是Y2K问题在作怪。电脑竟然将布洛杰特的年龄识别为1岁。这次的Y2K问题还牵出了之前一直未引起人们注意的政策性错误:20岁以下一律视为青少年,所以汽车保险费上涨了3倍……等等,1岁也算是青少年吗?
写给软件开发者的话
Zune 媒体播放器的用户论坛ZuneBoard 上,有人提出,2008 年12 月31 日发生的硬件故障来自Zune 的时钟驱动器。ID 名为“isnotabigtruck”的用户在网站公布了飞思卡尔处理器的时钟驱动源代码,并做出说明:“Zune 在启动过程的最后一个阶段第一次访问时钟驱动,将时钟变更为日期和时间。” 他给出的下列代码是从日期中计算年份。
请留意第9行代码。2008年是共有366 天的闰年,2008年12月31日是2008年的第366天。days 变量中输入366后,第9行的if语句会判断为false,然后移动到第20行。而days变量仍然是366,这样就会进入无限while 循环。
以上是飞思卡尔MC13783PMIC 处理器的驱动代码。当时,使用该处理器的东芝公司的Gigabeat S媒体播放器也曾出现类似情况。
本文选自《致命Bug》。
作者:金钟河
译者:叶蕾蕾
《致命Bug》通过软件史上的经典案例,介绍了软件故障引发的宇宙、航空、军事、通信、金融、医疗、生活等多领域的事故。即使不具备软件相关的专业知识,平时关注历史事件或热点话题的普通人也能受益匪浅。尤其是希望编写无Bug软件的开发人员或测试人员、经营软件公司的管理人员或高层人士等,更能从本书中获得丰富感受。
点击书名查看完整目录与试读。
阅读原文