开发人员不要只从名称上去理解这两套规则,它们虽然都面向C语言,也都可以帮助减少代码里的毛病,但处理问题的侧重点并不同。MISRA C会把注意力更多地放在代码写法是不是稳定、能不能被工具查出来,以及后期评审时团队能不能讲明白;CERT C则更关心代码会不会留下安全方面的隐患,比如内存使用越过了边界、整数计算结果溢出、资源用完后没有被释放、来自外部的数据没有做检查,这些都属于CERT C经常要查看的内容。项目团队可以把MISRA C当作基础的写法要求,再把CERT C看成安全问题的补充检查,这样在安排规则时方向会清楚一些。
一、MISRA C和CERT C的区别
MISRA C和CERT C对减少C代码的缺陷都有帮助,可是两者的重点并不一样。要是项目负责人只看到名字相近,就很容易把两种要求当成一回事,后续执行时也会解释不清楚。团队需要先看清项目的风险,再去决定把MISRA C和CERT C分别放进哪些环节里。
1、关注的问题不一样
MISRA C主要看嵌入式代码能不能稳定地运行。C语言里有许多写法表面上能跑通,但是换一种编译器、换一个芯片、换一组配置,代码的运行结果就有可能出现变化。指针转换、类型转换、宏定义、数组访问、位运算这些内容,如果开发人员没有写清楚,后面就容易引出麻烦。
CERT C把重点放在代码安全上,它会提醒开发人员哪些写法可能带来安全缺陷,哪些写法容易被外面的数据触发问题。字符串处理不够严格、缓冲区被越界使用、整数计算缺少边界检查、文件打开后没有正确关闭,这些内容更接近CERT C要检查的重心。
2、被用到的场景不一样
MISRA C更多出现在汽车电子、工业控制、医疗设备、轨道交通、航空航天配套设备等工程里。这些工程通常很难接受代码随便出错,代码不光要能运行,还应当能做出解释、能接受检查、能留下记录,到了后期评审阶段,团队也要能够把问题说得清清楚楚。
CERT C则更常见于那些安全要求比较高的软件工程里。如果产品带有通信接口、升级接口、数据导入、日志导出、远程诊断等功能,团队就要注意CERT C所提醒的那些事情,因为这些位置会接触到外部数据,安全风险更容易出现。
3、管理的方式不一样
MISRA C一般会融入开发流程里面。工程刚开始时,团队先要把规则确定下来;开发人员写代码的过程中,要用工具去做检查;评审人员看代码时,也要看检查报告。遇到不能修改的违规项,开发人员必须写清楚原因、影响范围,以及用什么样的测试来覆盖。
CERT C则更像一份安全检查表,团队既可以用它给代码做安全排查,也可以拿它做安全培训。CERT C不一定非要和功能安全流程绑在一起,但它对安全问题的提醒比较直接,安全人员拿着它去排查问题时,也比较容易找到输入处理、内存操作、计算过程和资源处理这些地方。
4、可以放在一起配合着用
MISRA C和CERT C并不是只能二选一。很多嵌入式工程可以把MISRA C当作基础的规则,再让CERT C去补充安全方面的要求。由MISRA C先管住代码的写法,再由CERT C从安全问题角度再检查一遍,这样做分工比较清楚,后期评审时也更容易去说明。
二、哪些嵌入式工程更适合用MISRA C
一个项目团队可以从代码出错后带来的影响去判断。如果代码出错只是让界面显示不对,那带来的影响可能还比较小;可要是设备动作、人员安全、现场生产或者客户验收会受到牵连,这样的工程就更适合把MISRA C用起来。
1、汽车电子工程
汽车电子工程里有很多C代码跑在电子控制单元、微控制器和各种控制器上。车身控制、底盘控制、电池管理、热管理、诊断通信这些模块,对代码质量的要求都比较高。开发团队不能只看代码能不能跑,还要尽量减少那些可能导致结果不确定的写法。
通过MISRA C,团队可以限制一些危险的写法。开发人员要把类型转换写清楚,使用指针时也要小心,不能随意去写宏定义;还要留意数组边界,因为这类问题在测试阶段不一定马上被发现,但之后却可能影响功能稳定。
2、工业控制工程
工业控制设备一般都需要长时间运行。运动控制器、机器人控制单元、可编程逻辑控制器扩展模块、仪器仪表、能源设备控制板等设备,常常要在现场环境里连续工作。现场一旦停机或者需要返工,都会带来成本,开发团队不能只靠后期去排查来补救问题。
这类工程用上MISRA C,主要是想减少那些隐藏起来的毛病。很多代码问题在实验室里不一定马上出现,等设备到了现场以后,负载可能发生改变,环境可能发生变化,通信条件也可能跟着变化,问题就容易在这些变化之后暴露出来。团队提前用规则把代码管住,后期再去排查问题就会省力很多。
3、医疗设备工程
医疗设备里的嵌入式代码,经常会和采集、控制、报警、数据处理这些功能打交道。监测设备、输注设备、检测仪器等产品,都需要比较稳当的软件表现。在这类工程里,开发团队不能只是把功能完成就算结束,还要考虑代码以后好不好检查和复查。
医疗设备工程用到MISRA C,并不只是为了让代码显得整齐。它能够为代码检查提供一个依据,开发人员为什么这样写,团队检查了哪些问题,哪些规则做了特殊处理,特殊处理又为什么可以被接受,这些内容都要能够说得清楚。
4、轨道交通和航空航天配套工程
轨道交通和航空航天配套工程的周期通常比较长,项目接口比较多,评审也很严格。软件到后期如果改动一次,团队可能要同步去修改文档、测试记录和交付材料,所以早期阶段的代码质量会影响到后面的工作量。
把MISRA C用起来,能帮团队在早期就拦住一部分问题。代码运行结果不稳定、表达式写得过于复杂、函数存在隐藏影响、底层类型转换不清楚,这些问题要是拖到集成阶段才去处理,团队就会花费更多时间。早一点把它们处理掉,后面就更容易把握项目的节奏。
5、由多家供应商配合的工程
有些嵌入式工程并不是由一个团队独立做完的,主机厂、一级供应商、模块供应商、外包团队都有可能交付代码。如果每个团队都按自己习惯来写,到了集成的时候,工作就会变得很乱。
MISRA C可以给不同的团队提供同一套检查标准,各个团队照着同样的规则去检查,问题就能更早被看到,项目负责人也更容易去判断问题该由谁负责。对由很多供应商一起配合的工程来说,统一的规则是非常有用的。
三、MISRA C在代码检查中怎样使用
想让MISRA C真正起到作用,团队不能等到代码全部写完才去检查,那样问题会堆在一起,开发人员也很难一次处理完。更合适的做法是从工程一开始,就把MISRA C放进开发流程里,让规则、自动检查工具、评审和特殊说明连在一起发挥作用。
1、团队要先把检查范围确定下来
工程刚开始时,团队要讲清楚哪些代码需要按照MISRA C来执行。与安全相关的模块、底层驱动、通信模块、控制算法模块,都可以被列入重点范围。第三方的代码、自动生成的代码、以前留下来的代码,也要提前说明该怎么处理。
团队不能省掉这一步。如果范围不明确,等到扫描报告出来以后,大家很容易为哪些问题要改、哪些问题不用改而争执,项目时间也会被这些争论消耗掉,开发人员还会觉得规则是后期才临时加上去的。
2、要把检查放进日常的开发活动里
MISRA C很适合配合自动检查软件来用。开发人员写完代码之后,可以先做一次基础检查;团队在做代码集成之前,可以再做一次完整的检查;到了项目快要发布的时候,还要确认所有问题是不是都已经处理好了。
自动检查软件虽然能发现很多问题,但它不能替团队做出所有的判断。代码是不是容易看懂,特殊处理是不是合理,模块之间的隔离是不是清楚,这些内容还是需要评审人员去查看。工具给出的报告只是证据的一部分,团队还要能把报告里的问题讲明白。
3、开发人员要把特殊处理写清楚
在嵌入式工程里,有些代码确实很难完全避开特殊的写法。像直接操作硬件寄存器、访问底层地址、编写中断处理、使用编译器扩展功能等,有时就会碰到MISRA C的规则。
开发人员遇到这类情况,不能只写一句“工程需要这样”,而要说明为什么一定要这样写,影响的范围在哪里,有没有做一些隔离处理,测试又是怎样去覆盖的,后期由谁来维护。把这些说明写清楚以后,评审人员才更容易接受。
4、可以用CERT C来补查安全问题
如果工程里包含了网络通信、文件解析、远程升级、日志导出、用户输入等功能,团队光看MISRA C还不够。这些地方更容易接触到外部数据,安全问题也更容易冒出来。
团队可以再参考CERT C去检查一次,重点检查内存的处理、字符串的处理、整数的边界、外部输入的检查以及异常处理等内容。经过这样一轮处理,代码的稳定性和安全性都能得到更好的把握。
总结
MISRA C和CERT C有什么区别,哪些嵌入式工程更适合用MISRA C,这个问题要回到工程的风险上去看。MISRA C更适合安全相关、需要长时间运行、评审要求清楚、有多家供应商协作的嵌入式C工程;CERT C更适合从安全问题角度去补做检查。汽车电子、工业控制、医疗设备、轨道交通、航空航天配套设备等工程,可以把MISRA C当成基础编码规则,同时也可以用CERT C去补充安全上的要求。这样写出来的代码,管理起来会容易一些,后期评审时也更容易讲清楚。