第一章:故障模型与失效模式

各位工程师朋友,咱们今天聊聊故障模型和失效模式。说实话,这是功能安全测试的根基。你连故障长什么样都不知道,怎么去测?怎么去防?

我在功能安全这行摸爬滚打十几年,见过太多因为对故障理解不透彻导致的返工。有一次,一个同事信誓旦旦说他的代码没问题,结果一跑故障注入,内存泄漏直接让系统在高温下崩溃。嗯,从那以后,他再也不敢小看故障模型了。

1.1 硬件故障模型

硬件故障,说白了就是芯片、电阻、电容这些物理器件出问题了。你想想看,一个焊点松了,或者一个MOS管烧了,系统会怎样?

我个人习惯把硬件故障分成三类:单点故障、潜伏故障、多点故障。这三类在ISO 26262里讲得很清楚,但实际项目中怎么用,我给大家拆开揉碎了说。

1.1.1 单点故障

单点故障,就是单个元件失效直接导致安全目标被违反。举个例子,刹车踏板的传感器坏了,你踩刹车没反应——这就是单点故障。

核心要点:单点故障必须被检测到,并且要在规定时间内响应。否则,安全机制就形同虚设。

我在一个ADAS项目中遇到过,一个摄像头电源管脚虚焊,导致图像信号间歇性丢失。单点故障,但很难复现。我们花了整整两周才定位到问题。

实战技巧:做单点故障注入时,别只盯着芯片内部。外部引脚、连接器、焊点,这些地方出问题的概率其实更高。

1.1.2 潜伏故障

潜伏故障,就是故障已经存在,但没被发现。它可能一直藏在系统里,等到某个关键时刻才爆发。

我曾经在一个工业控制器项目里,发现一个看门狗定时器的配置寄存器被写坏了。但系统没报错,因为故障被掩盖了。直到三个月后,现场设备死机,我们才追查到这个问题。

警告:潜伏故障是功能安全测试中最容易被忽略的。很多团队只测单点故障,不测潜伏故障。结果呢?安全机制本身可能已经坏了,你还以为系统是安全的。

潜伏故障的测试,我建议用周期性自检来覆盖。比如,每隔100ms检查一次安全机制的完整性。

1.1.3 多点故障

多点故障,就是两个或两个以上的独立故障同时发生。注意,是独立故障,不是同一个原因导致的。

举个例子,一个双冗余的传感器系统,一个传感器漂移了,另一个传感器也漂移了。两个故障独立发生,但叠加在一起,系统就误判了。

故障类型 定义 测试重点
单点故障 单个元件失效直接违反安全目标 检测时间、响应时间
潜伏故障 故障存在但未被发现 自检覆盖率、诊断间隔
多点故障 两个独立故障同时发生 故障组合、冗余管理

1.2 软件故障模型

软件故障,比硬件更头疼。硬件坏了你能换,软件坏了你得上千行代码里找bug。我见过太多因为软件故障导致的安全事故了。

1.2.1 内存泄漏

内存泄漏,就是申请了内存没释放。一次两次没事,但跑上几天几周,内存慢慢被吃光,系统就崩了。

我记得有个项目,一个通信模块每接收一条消息就malloc一次,但只在特定条件下才free。结果系统运行72小时后,内存耗尽,直接死机。

// 典型的内存泄漏示例
void process_message(uint8_t *data, uint32_t len) {
    uint8_t *buffer = (uint8_t *)malloc(len);
    // 处理数据...
    // 忘记 free(buffer) 了!
}

避坑指南:我曾经在代码审查时发现,很多工程师喜欢用全局变量来管理内存。这其实很危险。我建议用RAII(资源获取即初始化)模式,让对象的生命周期自动管理内存。

1.2.2 堆栈溢出

堆栈溢出,说白了就是函数调用太深,或者局部变量太大,把栈空间撑爆了。嵌入式系统里,栈空间通常只有几KB,一不小心就溢出了。

为什么会这样?你想想看,一个递归函数没有终止条件,或者一个结构体变量定义得太大,栈就爆了。

警告:堆栈溢出不会立刻报错。它可能表现为随机崩溃、数据被篡改、或者函数返回地址被覆盖。这是最危险的安全漏洞之一。

我建议在编译时开启栈保护(-fstack-protector),并且在运行时监控栈水位。我曾经在一个项目中,用栈哨兵(stack canary)技术,成功捕获了一个间歇性的栈溢出问题。

1.2.3 数据竞争

数据竞争,就是多个任务同时访问同一个变量,而且至少有一个是写操作。结果呢?数据不一致,系统行为不可预测。

多核系统里,数据竞争尤其常见。我记得有个项目,两个核同时更新一个全局计数器,结果计数器的值忽大忽小,导致控制逻辑完全错乱。

// 数据竞争示例
int counter = 0;

// 任务1
void task1(void) {
    counter++;  // 读-改-写操作
}

// 任务2
void task2(void) {
    counter++;  // 同时执行,导致数据丢失
}

实战技巧:数据竞争的测试,我建议用静态分析工具(比如Coverity、Polyspace)来扫描。动态测试很难复现,因为时序问题太随机了。

1.3 失效模式与影响分析(FMEA)

FMEA,说白了就是系统性地问自己:如果这个零件坏了,会怎样?影响多大?怎么预防?

我个人习惯把FMEA分成三步走:

  1. 列出所有可能的失效模式——比如电阻开路、电容短路、软件变量溢出
  2. 分析每个失效模式的影响——对系统功能、安全目标、用户体验的影响
  3. 制定应对措施——检测、容错、降级、报警

我在一个EPS(电动助力转向)项目中做过FMEA。我们发现,如果扭矩传感器的电源短路到地,系统会误判为无转向力矩,然后突然失去助力。这个失效模式的影响等级是S3(严重)。

应对措施是什么?我们加了一个电源监控电路,一旦检测到短路,立即切换到冗余电源。

核心要点:FMEA不是一次性的工作。它应该贯穿整个开发周期。设计变了,FMEA就要更新。我见过太多团队做完FMEA就扔一边了,结果后期改设计时,新的失效模式根本没被覆盖。

1.4 知识体系总览

下面这张图,是我自己总结的故障模型与失效模式的知识体系。你把它打印出来贴在工位上,做测试时对照着看,基本不会漏。

故障模型与失效模式知识体系 硬件故障模型 软件故障模型 FMEA 单点故障 潜伏故障 多点故障 内存泄漏 堆栈溢出 数据竞争 失效模式→影响→措施 测试方法:故障注入 + 失效分析 输出:安全机制设计 + 测试用例 最终目标:系统功能安全

这张图的核心逻辑是:从硬件和软件的故障模型出发,通过FMEA分析,设计测试方法,最终输出安全机制和测试用例。每一步都不能少。

我的建议:刚开始做功能安全测试的工程师,别急着上手写测试用例。先把故障模型搞清楚,把FMEA做扎实。基础打好了,后面的工作就是水到渠成的事。


公众号:蓝海资料掘金营,微信deep3321