华为的鸿蒙手机操作系统已经发布了几个月了,作为国产操作系统,其寄托了我们的深切希望。在鸿蒙系统发布会上,手机、平板、智能手表等消费电子类产品固然是主角,而作为华为冉冉升起的新兴业务领域——智能汽车,亦被包含在系统生态之中,也引起了行业的广泛关注。
鸿蒙作为一个新生的系统,其不可避免的会存在很多问题,而汽车领域对代码的编码规范要求又极为严格。因此本文将通过使用汽车行业主流的静态分析工具,来分析测试鸿蒙系统代码对汽车行业内常用编码规范(CERT、MISRA C 2012、CWEC)的遵循情况。
考虑到标准鸿蒙系统的代码量非常庞大,本文仅以OpenHarmony_1.0.1_release分支中的Hi3861 WLAN模组代码为例进行部分代码的静态测试。
Ubuntu编译环境准备
系统要求:Ubuntu16.04及以上64位系统版本。
本文使用的是搭建在虚拟机中的Ubuntu 18.0系统,编译环境搭建分为如下步骤:
▲获取源码
▲安装和配置Python
▲安装gn
▲安装ninja
▲安装LLVM
▲安装hb
了解详细的配置步骤请移步鸿蒙开源项目教程指南,本文就不做详细的介绍了,按照文档一步一步进行操作,就可以获取鸿蒙轻量系统源码,并完成编译环境的搭建。
请注意,此时我们还无法编译鸿蒙系统,需要完成后续开发板环境搭建后才能正常编译鸿蒙系统。
Hi3861开发板环境搭建
为了能正常编译源码中的wifiiot_hispark_pegasus工程,我们需要在刚才设置的Ubuntu编译环境中搭建Hi3861开发板环境搭建,如果需要编译别的工程,搭建对应的开发板环境即可。
了解详细的搭建步骤请移步安装Hi3861开发板环境。
完成Hi3861开发版环境搭建后,我们就可以正常编译源码中的wifiiot_hispark_pegasus工程了,具体步骤如下:
▲到下载的源码根目录下,执行hb set,然后会提示让你输入源码根目录,输入当前路径后回车,选择wifiiot_hispark_pegasus项目就完成了编译准备工作。
▲执行hb build即可进行wifiiot_hispark_pegasus工程的编译,如果编译结果如下图所示,即表示你成功地编译了该工程。
成功实现wifiiot_hispark_pegasus工程的编译后,我们就可以进行后续的静态分析工作了。
鸿蒙系统编译环境配置
通过编译器环境配置文件生成工具,我们可以很方便地生成鸿蒙编译环境的配置文件,由于wifiiot_hispark_pegasus工程是C工程,因此只配置C编译器的环境即可,考虑到鸿蒙使用的是C99标准,因此需要在生成配置文件时需要添加-std=C99,具体如下图:
然后在静态测试工具中导入该配置文件即可。
为了方便后续将鸿蒙的静态分析过程部署到持续集成平台上,本文以命令行的方式进行静态分析操作的演示。具体步骤如下:
▲创建QAC工程,命令如下:
qacli admin --qaf-project-config --qaf-project . --cct "/home/zhou/.config/Perforce/Helix-QAC-2021.1/config/cct/GNU_GCC-riscv32-unknown-elf-gcc_7.3.0-riscv32-unknown-elf-C-c99.cct"--acf"/home/zhou/.config/Perforce/Helix-QAC-2021.1/config/acf/HMOS.acf"--rcf "/home/zhou/.config/Perforce/Helix-QAC-2021.1/config/rcf/HMOS.rcf"
为了更全面地了解鸿蒙系统的代码质量,本文在QAC工程的分析配置文件HMOS.acf中添加了MISRA C 2012合规模块、CERT C合规模块及CWE C合规模块。
①MISRAC 2012:为开发安全关键系统提供编码标准,广泛应用于汽车软件开发。
②CERT :信息安全编码标准,能确保您的软件免受潜在的软件安全漏洞的侵害。
③CWEC:常见弱点枚举(CWE)列表标识了软件和硬件中的软件安全弱点。
▲过滤鸿蒙中包含的第三方源码,命令如下:
qacli pprops -P . --sync-setting FILE_FILTER --set"/home/zhou/Downloads/openHarmony/third_party"
通过该命令,我们可以将鸿蒙工程中包含的第三方源码从QAC工程中过滤出去,这样我们可以更好地通过QAC的分析结果衡量鸿蒙源码的代码质量。
▲将wifiiot_hispark_pegasus工程源码加载到QAC工程中,具体命令如下:
qacli sync -P . -t MONITOR "cd /home/zhou/Downloads/openHarmony&&hbclean&&hb build"
该命令是通过监测wifiiot_hispark_pegasus工程的编译过程,自动将编译过程中调用的源文件和头文件添加到QAC工程中。
▲执行QAC分析,具体命令如下:
qacli analyze -P . –cf
▲生成合规报告:
qacli report -P . -t RCR
▲将分析结果上传到QAC的网页端,方便查看,命令如下:
qacli upload -P . --qav-upload --upload-project HMOS--snapshot-name v1.0 --upload-source ALL -U https://192.168.9.126:8081/--username admin --password admin
静态分析结果分析
模块wifiiot_hispark_pegasus的总体合规情况如下:
QAC共计报出107618条诊断消息,共计违反规则290264次,违反的规则数目为302条(包含MISRA C、CERTC和CWE C),符合的规则有216条,由于模块的文件合规率高达94.19%,但是工程合规率却只有41.70%,所以可以看出违反规则的情况集中在少部分源文件中。
wifiiot_hispark_pegasus源码的CERT总体违规情况如下图:
图中的图例为CERT C的规则组简写,详细信息如下:
02_DCLDeclarations and Initialization (DCL)
10_ENVEnvironment (ENV)
11_SIGSignals (SIG)
04_INTIntegers (INT)
09_FIOInput Output (FIO)
14_CONConcurrency (CON)08_MEM Memory Management (MEM)
07_STRCharacters and Strings (STR)
03_EXPExpressions (EXP)
违反最多的10条CERT C规则如下图:
CERT C规则的违规分布情况如下图:
图中方块面积表示代码量,颜色深浅表示违反CERT的严重程度,由上图可以看出,CERT C的违规情况主要集中在如下源文件中:
▲cmsis_task_func_test.c:有3182行代码,违反了1951条CERT C的诊断消息;
▲cmsis_task_pri_func_test.c有1635行代码,违反了1144条CERT C的诊断消息;
▲tcp_session_manager.c:有1230行代码,违反了912条CERT C的诊断消息;
▲huks_adapter.c:有1705行代码,违反了862条CERT C的诊断消息;
▲coap_adapter.c:有638行代码,违反了579条CERT C的诊断消息。
圈复杂度最高的10个函数如下图:
下文我们将摘录部分违反规则的代码进行分析说明:
1. DCL37 Do not declare or define a reserved identifier. (rule)
规则解释:
根据 C 标准,7.1.3 [ ISO/IEC9899:2011 ],
所有以下划线和大写字母或其他下划线开头的所有标识符都始终保留使用。
所有以下划线开头的标识符始终保留,用作普通名称空间和标签名称空间中文件范围的标识符。
违规举例:
/HMOS/base/hiviewdfx/hievent_lite/frameworks/hiview_event.c,L28:
#define EVENT_VALUE_MAX_NUM 16
此处代码不合规,因为'EVENT_VALUE_MAX_NUM'宏可能在未来与'<errno.h>'中的宏有冲突。
参考ISO:C90Language [7.13], ISO:C99 Language [7.26]
2. INT02 Understand integer conversion rules. (recommend)
规则解释:
转换可以作为强制转换的结果显式发生,也可以根据操作的要求隐式发生。尽管正确执行程序通常需要进行转换,但它们也可能导致数据丢失或被误解。将操作数值转换为兼容类型不会导致值或表示发生变化。
C 整数转换规则定义了 C 编译器如何处理转换。这些规则包括整数提升、整数转换等级和通常的算术转换。规则的意图是确保转化导致相同的数值,并且这些值最小化了其余计算中的意外。Prestandard C 通常更倾向于保留类型的签名。
违规举例:
/HMOS/base/hiviewdfx/hievent_lite/frameworks/hiview_event.c,L57:e.common.mark = EVENT_INFO_HEAD;
此处代码不合规,因为一个'essentially signed'类型的整型常量在赋值时被转换为'unsigned'类型。
3. DCL23 Guarantee that mutually visible identifiers are unique.(recommend)
规则解释:
根据 C 标准 [ ISO/IEC9899:2011 ] 的第 6.2.7 条,
所有引用同一对象或函数的声明都应具有兼容的类型;否则,行为未定义。
此外,根据第 6.4.2.1 款,
任何在重要字符上不同的标识符都是不同的标识符。如果两个标识符仅在非重要字符上不同,则行为未定义。
违规举例:
/HMOS/base/hiviewdfx/hievent_lite/interfaces/native/innerkits/hiview_event.h,L85:
void HiEventPutInteger(HiEvent *event, int8key, uint32 value);
此处代码不合规,因为外部标识符匹配其他外部标识符(例如:'HiEventPrintf')的前6个字符-程序不符合严格的ISO:C90。
参考:ISO:C90 Language [6.1.2],Security Problems
4. DCL00 Const-qualify immutable objects. (recommend)
规则解释:
不可变对象应该使用const限定。使用const限定来强制对象不变性有助于确保应用程序的正确性和安全性。例如,ISO/IEC TR 24772 建议将参数标记为常量,以避免无意中修改函数参数 [ ISO/IEC TR 24772 ]。STR05-C. Use pointers to const when referringto string literals描述了此建议的特殊情况。
违规举例:
/HMOS/base/hiviewdfx/hievent_lite/frameworks/hiview_event.c,L50:
void HiEventPrintf(uint8 type,uint16 eventId, int8 key, uint32 value)
此处代码不合规,因为形参'type'永远不会被修改,因此可以用'const'限定符声明它。
参考:, ISO:C90Language [6.5.3], Security Problems
5. MEM34-C. Only free memory allocated dynamically.(rule)
规则解释:
C标准附录J [ISO/IEC 9899:2011]指出,如下行为是未定义的:
free或realloc函数的指针参数与先前由内存管理函数返回的指针不匹配,或者空间已被调用free或realloc释放。
释放非动态分配的内存可能导致堆栈损坏和其他严重错误。不要对非标准内存分配函数返回的指针调用free(),如malloc()、calloc()、realloc()或aligned_alloc()。
违规举例:
/HMOS/base/security/deviceauth/frameworks/deviceauth_lite/source/struct/parsedata.c,第76行代码:
FREE((char *)payload);
此处代码不合规,因为这是对非动态内存palyload变量的释放,payload定义在/HMOS/base/security/deviceauth/frameworks/deviceauth_lite/source/struct/parsedata.c,L53:
payload = json_to_string(obj_value);
限于篇幅,MISRA C和CWE C的合规情况不在这里一一展示。
通过对鸿蒙系统部分代码的静态测试,我们尝试了解了鸿蒙系统针对汽车行业常用的代码编程规范的合规情况,期望未来鸿蒙通过不断迭代开发,提升代码的合规程度,进一步改善代码的质量,成为一个优秀的车载操作系统。