你可能写过无数个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":传感器错了,飞机就栽了。
四个案例,一个共同点
回头看这四个事故,技术上有难有易,行业各不相同,但有一个规律高度一致:
每一个事故的直接原因都只是一个小Bug。真正致命的是:流程缺失、验证不足、安全意识淡薄。
这不是某个程序员写错了if的问题,是整个工程体系的问题。所以后来业界出了一整套东西来解决这个问题——功能安全标准。
功能安全标准,就是用流程防人犯蠢
Therac-25 事故之后,医疗设备领域开始强制要求软件安全验证。Ariane 5 之后,航天领域建立了更严格的代码复用审查流程。丰田事件之后,汽车行业加速推进 ISO 26262。737 MAX 之后,航空领域重新审视了"单点故障"的设计准则。
这些标准本质上都在做同一件事:用流程和规则,确保软件不会因为一个Bug伤人。
你可能会想,我的代码又不控制火箭也不控制汽车,跟我有什么关系?
想想你写过的代码—— 电梯控制?医疗设备?充电桩?自动驾驶?工业机器人? 这些领域现在都在招"懂功能安全"的程序员,薪资比普通开发高 30%~50%。 |
功能安全不是只有航天和核电才需要的东西。新能源车、工业控制、医疗电子、智能硬件——凡是软件出错可能伤人的场景,都在往这个方向靠。
有风险不可怕,可怕的是不知道有风险。功能安全这套东西,就是一套系统化的方法,让你知道风险在哪、怎么控、控到什么程度才算够。
如果这篇让你第一次认真想了想"我的代码会不会伤人",点个在看。
我是会摸鱼的程序员,今天不摸鱼,今天是搞功能安全的程序员,在一家做控制系统的公司写嵌入式 C,研究怎么把fail-safe落到实处。 嵌入式 / C / 功能安全 |
夜雨聆风