乐于分享
好东西不私藏

软件Bug杀过人 你可能不知道

软件Bug杀过人 你可能不知道

你可能写过无数个Bug,修过无数个Bug,但你有没有想过一个问题——

软件Bug,杀过人吗?

我第一次认真想这个问题的时候,也觉得不太可能。代码嘛,跑不通就改,改完再测,顶多线上事故回滚一下。

后来我接触了功能安全,翻了几个经典案例——如果把历史上因为软件缺陷导致的事故加在一起,至少500人以上

下面这四个故事,是功能安全领域最经典的案例。每一个都不是段子,每一条人命都是真实的。

放射治疗机,6人因软件缺陷死亡

Therac-25,1985年到1987年间北美使用的放射治疗设备。用它治疗癌症,结果有些患者死在了治疗过程中。

Bug 是什么?操作员输入剂量时,如果快速修改参数,软件的竞态条件会让高能射线以正常剂量的100倍照射患者。屏幕上只显示"Malfunction 54",没有任何解释。

更离谱的是:操作员多次报告异常,厂家工程师到场后觉得"机器没问题,是操作失误",回去没做任何修改。

时间:1985 - 1987

设备:Therac-25 放射治疗机

根因:多线程竞态条件 + 软件独占了安全联锁(硬件保护被去掉)

后果:至少6人过量辐射,其中多人死亡

后来的调查报告里有一句话被反复引用:开发者认为软件不会出错,所以把硬件安全联锁去掉了——软件成了唯一的保护层,而它没有经过任何安全验证。

火箭发射37秒爆炸,因为一个整数溢出

1996年6月4日,欧洲空间局的 Ariane 5 火箭首飞。发射后37秒,火箭偏航,自动解体,连带着4颗卫星一起炸成了烟花。

直接损失:5亿美元。

调查结果让人哭笑不得:一个64位浮点数(火箭的水平速度)被转成了16位有符号整数,数值溢出了。这段代码是从 Ariane 4 那边直接搬过来的——在4号火箭上数值范围没问题,换了5号之后水平速度超出预期,溢出触发异常,主控计算机直接崩溃。

时间:1996-06-04

项目:Ariane 5 火箭首飞

根因:64位浮点 → 16位整数,溢出未捕获

后果:火箭自毁,损失5亿美元,无人员伤亡

这段Bug代码的位置——一个叫水平速度偏置的函数,在火箭升空后的37秒内根本用不到。它之所以还在跑,纯粹是因为没人分析过这段代码在新环境里是否还需要

事后调查报告的结论:不是技术不行,是需求分析和变更管理流程出了问题——代码复用没有经过完整的验证。

900万辆车被召回,软件里藏着一个"幽灵踏板"

2009年到2010年,丰田"意外加速"事件席卷全球。车主报案称:正常行驶时车辆突然加速,刹车踩不下去,最终酿成事故。

丰田最初坚称是脚垫卡住了油门踏板。但NASA和美国交通部介入调查后发现,问题更深层:发动机控制软件里存在复杂的任务调度和优先级翻转问题,在某些极端条件下,CPU资源被占满,刹车信号无法及时响应。

时间:2009 - 2010

事件:丰田意外加速(Unintended Acceleration)

根因:任务调度 + 优先级反转 + 堆栈溢出(综合软件缺陷)

后果:全球召回900万辆车,赔偿超过10亿美元

NASA的最终报告说了一段很克制的话:"虽然没有找到明确的软件缺陷导致意外加速的直接证据,但丰田的软件设计存在严重的工程缺陷,不具备足够的安全保护机制。"

翻译成人话:软件本身不一定是凶手,但软件的设计没有做到"即使出错了也不会伤人"——而这,恰恰是功能安全的核心思想。

两次空难346人遇难,原因是一行代码的逻辑缺陷

2018年10月,印尼 Lion Air JT610航班起飞13分钟后坠海,189人遇难。2019年3月,埃塞俄比亚航空 ET302航班起飞6分钟后坠毁,157人遇难。

两起事故的根因指向同一个系统:MCAS(机动特性增强系统)。这是波音为737 MAX新加的飞控软件,用来补偿发动机位置变更带来的抬头趋势。

MCAS的设计有一个致命缺陷:它只依赖一个迎角传感器的数据。当这个传感器给出错误读数时,MCAS会反复压低机头,而且飞行员每次手动拉起后,MCAS会在5秒后再次介入——飞行员根本拉不住

时间:2018-10 / 2019-03

事件:Boeing 737 MAX 两起空难

根因:MCAS 单点传感器依赖 + 飞行员未被告知系统存在

后果:346人遇难,737 MAX全球停飞20个月

最让人心寒的不是Bug本身,而是:飞行员不知道MCAS的存在。波音为了减少飞行员培训成本,在手册里没有说明这个系统。当飞机不受控制地低头时,飞行员面对的是一个他们完全不知道的对手。

功能安全里有一句话叫"fail-safe"——系统坏了也不能伤人。MCAS恰恰相反,它做到了"fail-deadly":传感器错了,飞机就栽了。

四个案例,一个共同点

回头看这四个事故,技术上有难有易,行业各不相同,但有一个规律高度一致:

事故
直接原因
深层原因
Therac-25
竞态条件
去掉硬件保护层,软件当唯一防线
Ariane 5
整数溢出
代码复用未验证,无变更分析
丰田
任务调度异常
安全机制不足,缺乏失效安全设计
737 MAX
单点传感器
减少培训成本,隐瞒系统存在

每一个事故的直接原因都只是一个小Bug。真正致命的是:流程缺失、验证不足、安全意识淡薄

这不是某个程序员写错了if的问题,是整个工程体系的问题。所以后来业界出了一整套东西来解决这个问题——功能安全标准

功能安全标准,就是用流程防人犯蠢

Therac-25 事故之后,医疗设备领域开始强制要求软件安全验证。Ariane 5 之后,航天领域建立了更严格的代码复用审查流程。丰田事件之后,汽车行业加速推进 ISO 26262。737 MAX 之后,航空领域重新审视了"单点故障"的设计准则。

这些标准本质上都在做同一件事:用流程和规则,确保软件不会因为一个Bug伤人。

你可能会想,我的代码又不控制火箭也不控制汽车,跟我有什么关系?

想想你写过的代码——

电梯控制?医疗设备?充电桩?自动驾驶?工业机器人?

这些领域现在都在招"懂功能安全"的程序员,薪资比普通开发高 30%~50%。

功能安全不是只有航天和核电才需要的东西。新能源车、工业控制、医疗电子、智能硬件——凡是软件出错可能伤人的场景,都在往这个方向靠。

有风险不可怕,可怕的是不知道有风险。功能安全这套东西,就是一套系统化的方法,让你知道风险在哪、怎么控、控到什么程度才算够。

如果这篇让你第一次认真想了想"我的代码会不会伤人",点个在看。

我是会摸鱼的程序员,今天不摸鱼,今天是搞功能安全的程序员,在一家做控制系统的公司写嵌入式 C,研究怎么把fail-safe落到实处。

嵌入式 / C / 功能安全