ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

汽车电子ISO 26262功能安全系列(第27期):软件单元设计与安全编码规范——写出“不会杀人”的代码

汽车电子ISO 26262功能安全系列(第27期):软件单元设计与安全编码规范——写出“不会杀人”的代码 软件单元设计 把架构图中的“大盒子”拆分成“小函数”并确定每个函数“该干什么、不该干什么、出错了怎么办”。第一步软件单元设计——把“大盒子”拆成“小函数”软件架构设计把系统分成了SWC软件组件——比如“跟车距离计算SWC”“雷达数据采集SWC”。但一个SWC可能包含几千行代码不能直接写。需要继续拆分——拆成软件单元Software Unit。软件单元 最小的可测试软件模块通常是一个函数Function或方法Method。单元设计的六大核心原则ISO 26262-6:2018的表6定义了软件单元设计的六大设计原则原则大白话为什么重要基于架构“单元设计必须跟着架构走”架构是“蓝图”单元是“砖块”——砖块不能乱砌简单性“能用10行写完绝不写100行”越复杂的代码越容易出bug可读性“代码是写给人看的顺便让机器跑”别人看不懂的代码谁也维护不了️鲁棒性“输入再离谱代码也不能崩”安全系统必须能在各种异常情况下稳定运行可修改性“改一个功能不用重写整个模块”软件是要持续迭代的可测试性“每个函数都得能单独测试”测不了的代码等于没写这些原则不是“建议”是“强制要求”——审核员会逐条检查你的单元设计是否满足这些原则。ISO 26262的“四大金刚”设计细则除了六大原则ISO 26262还规定了四个更具体的设计细则细则1强类型Strong Typing每个变量必须明确指定数据类型不允许随意进行类型转换。细则2防御性编程Defensive Programming永远不要相信输入数据。每一个可能出错的地方都要做检查。细则3接口严格定义Strict Interface Definition函数之间怎么传递数据必须在接口层面说清楚——参数类型、取值范围、返回值含义一个都不能少。细则4高内聚High Cohesion一个函数只做一件事。如果一个函数做了三件不同的事拆成三个函数。实战ACC控制器单元设计场景把“跟车距离计算SWC”拆分成软件单元软件单元功能输入输出设计原则get_radar_distance()读取雷达目标距离雷达ID距离(m)强类型防御性get_relative_speed()计算相对速度两次距离时间差相对速度(m/s)简单性可测性calc_safe_distance()计算安全跟车距离本车速度安全距离(m)高内聚可读性check_following()判断是否安全实际距离安全距离TRUE/FALSE鲁棒性可修改性第二步安全编码规范——MISRA是“必修课”单元设计做完终于可以写代码了。但功能安全的代码不是“能跑就行”。ISO 26262 Part 6要求必须应用编码标准来实现特定的编码和设计指南。而在汽车行业这个编码标准的“代名词”就是MISRA。MISRA是什么MISRA全称是“Motor Industry Software Reliability Association”汽车工业软件可靠性协会。MISRA C是专门为C语言开发的安全关键系统编码标准旨在提升软件的安全性、可靠性、可维护性和可移植性。MISRA不是“建议”是汽车行业安全关键软件的“必修课”——不遵守MISRA的代码功能安全审核根本过不了。MISRA C:2025的核心数据统计项数据总指南数223条指令Directives22条规则Rules201条新增规则4条MISRA C:2025最重要的新增规则对联合体union非活跃成员读取的限制——这种操作会导致“实现定义行为”不同编译器结果不同是安全关键系统的重大隐患。MISRA为什么重要在C语言中有几百种指令和结构其中一些非常容易出错。MISRA通过禁止使用这些容易出错的函数和结构让代码更不容易出bug。被MISRA禁止的常见“危险操作”危险操作为什么危险MISRA怎么说strcpy()不检查目标缓冲区大小→可能溢出禁止使用改用strncpy()或memcpy()gets()无法限制输入长度→缓冲区溢出完全禁止malloc()/free()动态内存分配可能失败→内存泄漏ASIL-D中禁止动态内存分配union非活跃成员读取行为由编译器决定→不同平台结果不同新增限制指针与NULL隐式比较容易导致空指针解引用新增规定实战MISRA合规的ACC代码不安全代码违反MISRA第三步静态分析——让工具帮你“抓bug”手动检查代码是否符合MISRA就像手动检查100万行代码里有没有拼写错误——不现实。ISO 26262要求使用静态分析工具来强制执行编码标准。静态分析工具可以在不运行代码的情况下自动扫描源代码发现 MISRA违规 潜在的缓冲区溢出 空指针解引用 未初始化的变量 死代码永远不会执行的代码主流静态分析工具工具特点适用场景Perforce QAC专注MISRA深度检查汽车行业首选ASIL-D项目Polyspace形式化方法数学级别完备性最严格的安全认证Parasoft C/CtestAI辅助静态分析敏捷开发功能安全LDRA Testbed静态单元测试一体化全流程验证静态分析不是“可选”是“强制”。ISO 26262要求所有安全相关代码都必须通过静态分析才能进入下一步。第四步单元测试与覆盖率——“测到100%才算数”代码写完了静态分析也过了。但没测过的代码不能证明它是安全的。单元测试的目标根据ISO 26262软件单元验证需要达成以下目标✅ 验证软件单元实现与详细设计、需求规格一致✅ 尽早隔离代码缺陷降低后期修复成本✅ 满足ISO 26262 ASIL等级覆盖率要求✅ 形成可追溯的功能安全证据覆盖率要求ASIL等级对照表这是ISO 26262最硬核的要求之一ASIL等级语句覆盖分支覆盖MC/DC覆盖ASIL A≥80%≥70%不强制ASIL B80%~100%80%~100%可选ASIL C100%100%≥90%~100%ASIL D100%100%100%ASIL-D要求MC/DC达到100%——这意味着代码中每一个条件的所有可能组合都必须被测试覆盖。MC/DC到底是什么MC/DC Modified Condition/Decision Coverage修正条件/判定覆盖它是最严格的代码覆盖率标准。要满足MC/DC你需要测试4种组合测试用例sensor_okdistance SAFE结果覆盖了什么TC-01✅ TRUE✅ TRUETRUE条件为真TC-02❌ FALSE✅ TRUEFALSEsensor_ok单独影响结果TC-03✅ TRUE❌ FALSEFALSEdistance单独影响结果TC-04❌ FALSE❌ FALSEFALSE条件为假对于复杂的逻辑比如if (A B C)测试用例数量会指数级增长——这就是为什么ASIL-D的单元测试那么耗时。主流单元测试工具工具特点适用场景Tessy嵌入式C/C单元测试有功能安全认证ASIL-D项目Google Test开源功能强大AUTOSAR AP平台CppUTest轻量级适合嵌入式资源受限的ECUCantataMC/DC分析能力强高安全等级项目实战ACC控制器单元设计全流程把以上所有内容整合起来ACC控制器的单元设计完整流程是这样的Step 1拆分软件单元软件单元功能输入输出ASILget_radar_distance()读取雷达数据雷达ID距离(m)Dcalc_safe_distance()计算安全距离本车速度安全距离(m)Dcheck_following()判断跟车状态实际距离安全距离TRUE/FALSEDformat_display()格式化显示数据原始数据显示字符串BStep 3MISRA合规检查使用静态分析工具如Perforce QAC扫描代码确保✅ 没有使用strcpy()、gets()等危险函数✅ 所有指针都有NULL检查✅ 所有数组访问都有边界检查✅ 没有未使用的变量Step 4单元测试对calc_safe_distance()进行单元测试用例ID输入(speed, weather)预期输出覆盖目标TC-001(60, 0)26正常晴天TC-002(60, 1)36正常雨天TC-003(60, 2)46正常雪天TC-004(-1, 0)-1边界值速度过低TC-005(131, 0)-1边界值速度过高TC-006(60, 3)-1边界值天气无效软件单元设计中容易踩的“坑”坑1把设计文档和代码分开写❌ 设计文档写一套代码写另一套两者对不上✅ 设计文档和代码必须保持一致——审核员会检查可追溯性坑2只做静态分析不做单元测试❌ “静态分析都过了代码肯定没问题”✅ 静态分析只能发现语法和结构问题发现不了逻辑错误——两者缺一不可坑3为了凑覆盖率而写“无效测试”❌ 写一些只为了“跑过代码”但啥也没验证的测试用例✅ 每个测试用例都必须有明确的验证目标和预期结果坑4忘记建立可追溯性❌ 测试用例和需求之间没有关联✅ 建立SSR ↔ 单元设计 ↔ 代码 ↔ 测试用例的完整追溯链
返回列表