千亿崩盘:从 0 数到 21,一行代码如何瘫痪全球?

随波逐码9个月前北京
随波逐码
以键盘为笔,代码写热爱;以 bug 为阶,打磨成长路。记录开发点滴、拆解技术难题,做有温度的技术分享,和大家在编程路上共赴山海~
32篇原创内容
摘要 美国网络安全公司CrowdStrike的安全软件更新引发的全球 Windows 设备蓝屏事件,仅仅源于它的代码试图去读取一个长度为20的数组中的第21个值



时间回到2024年7月,美国网络安全公司CrowdStrike的安全软件更新引发的全球 Windows 设备蓝屏事件,该事件波及数十个国家,航空、金融、医疗等关键行业受创严重,出现航班停飞、金融交易中断、医疗活动停滞等情况。事件造成的潜在经济损失接近 1000 亿美元;且影响持续时间长,事发 5 天后仍有 3% 的蓝屏设备未恢复,直至第 10 天左右才基本恢复正常。谁曾想到,这一灾难性的事件仅仅源于它的代码试图去读取一个长度为20的数组中的第21个值。这就像是一个只有20个格子的文件柜,代码却非要去拿第21个格子里的东西,但这个格子根本不存在,一伸手就把整个柜子掀翻了。这也就是差一错误(Off-by-one error)。

差一错误源于现代计算机语言默认使用的零索引写法,这就要求程序员总是从0开始数数,然而人们也习惯于从1开始数数。很多学习编程的人都会有一个疑问,为什么索引是从0开始的?

从早期的 C 语言开始,数组在内存中是连续存储的,而所谓索引,本质上代表的是 “相对于数组起始地址的偏移量”。这里的 “0”,意思就是 “没有偏移”,直接对应数组第一个元素的起始位置。这样一来,计算任意元素的内存地址时,只需用数组起始地址 + 索引 × 单个元素长度就能得出,不需要额外加1,运算效率因此更高。但是后来发明了其它编程语言的人,都开在数组的开头放入大量的元数据(Metadata,用于描述数据的数据),并且他们还使用了各种新型的数据结构,这些新型数据结构往往不会把数据放在一个内存片区,从而提高内存的利用率和操作效率。因此,这些语言的数组也不再依赖于“数组起始地址的偏移量”,而开始使用了真正的索引。让人费解的是,索引完全可以从1开始数,但这些编程语言的发明者却莫名其妙地延续了从0开始的数数方式。

这场千亿损失的灾难,本质是人性与规则的错位。编程语言发明者早已熟稔零索引逻辑,甚少出错,但普通程序员难逃 “从 1 计数” 的直觉本能,再加上认知偏差与熟悉盲点,差一错误便成了高频 “人性 Bug”。


阅读 27
免责说明:对于用户内容中涉及的观点、建议、数据等,仅代表发布者个人立场,不视为平台官方观点,平台不对其真实性及可行性作出承诺。
if($('#ad_list_1').length>0){ gubel.api.gdtor(gdtdata=>{ setTimeout(()=>{ gdtdata.push({ app_id: '1218616126', placement_id: '5352294086181369', type: 'native', muid_type: '1', count: 10, onComplete: function(res) { if (res && res.constructor === Array) { gdtdata.NATIVE.renderAd(res[0], 'ad_list_1'); gdtdata.NATIVE.renderAd(res[1], 'ad_list_2'); gdtdata.NATIVE.renderAd(res[2], 'ad_list_3'); gdtdata.NATIVE.renderAd(res[3], 'ad_list_4'); gdtdata.NATIVE.renderAd(res[4], 'ad_list_5'); gdtdata.NATIVE.renderAd(res[5], 'ad_list_6'); gdtdata.NATIVE.renderAd(res[6], 'ad_list_7'); gdtdata.NATIVE.renderAd(res[7], 'ad_list_8'); gdtdata.NATIVE.renderAd(res[8], 'ad_list_9'); gdtdata.NATIVE.renderAd(res[9], 'ad_banner_1'); } else { } } }); }, 3000); }); }else{ gubel.api.gdtor(gdtdata=>{ setTimeout(()=>{ gdtdata.push({ app_id: '1218616126', placement_id: '1302499096588067', type: 'native', display_type: 'interstitial', count: 1, onComplete: function(res) { if (res && res.ret === 0) { gdtdata.NATIVE.renderAd(res.data[0]); } else { } } }); }, 3000); }); }
© 2025-2026 ® All Rights Reserved.
{{item}}
setTimeout(()=>{ gubel.api.embedor(); }, 2000);
客服