MISRA-C2012

概述

XWOS的代码,大致遵循 MISRA-C:2012 规范进行编写,但有些 MISRA-C:2012 的规则不利于 编写操作系统,XWOS的代码趋向于选择更优的性能以及尝试使用更新的语言特性。

本文将详细描述 MISRA-C:2012 检查的方法,以及 MISRA-C:2012 规范的符合程度。

MISRA-C:2012 规范的检查方法

使用 cppcheck 工具的 misra 插件。

cppcheck -I. -I$(XWOS_ARCH_DIR) -I$(XWOS_CPU_DIR) -I$(XWOS_SOC_DIR) -I$(XWOS_BRD_DIR) \
  --force --addon=misra --cppcheck-build-dir=$(CPPCHECK_OUT) \
  --template=gcc --inline-suppr --suppressions-list=xwbs/util/cppcheck/misra-c2012-suppressions.txt
  -i ignore_path src_path

MISRA-C:2012 规范的符合程度

全局禁用的规则

  • uninitvar

    • 禁用原因:误报。实际上未初始化变量,编译器会当成错误来处理。
  • misra-c2012-1.4 : Emergent language features shall not be used

    • 禁用原因:作为一个长期持续维护的项目,XWOS在新版本中会偏向于引入新的语言特性。
  • misra-c2012-2.3 : A project should not contain unused type declarations

    • 禁用原因:操作系统作为一个 生态系统 的基本环境,其中定义的类型、宏、函数、符号等可能在各种衍生项目中被用到。
  • misra-c2012-2.4 : A project should not contain unused tag declarations

    • 禁用原因:操作系统作为一个 生态系统 的基本环境,其中定义的类型、宏、函数、符号等可能在各种衍生项目中被用到。
  • misra-c2012-2.5 : A project should not contain unused macro declarations

    • 禁用原因:操作系统作为一个 生态系统 的基本环境,其中定义的类型、宏、函数、符号等可能在各种衍生项目中被用到。
  • misra-c2012-3.1 : The character sequences /* and // shall not be used within a comment

    • 禁用原因:XWOS内使用doxygen来抓取注释生成文档,文档中如果出现URL,必然会出现 // ,例如 https://... ,除此种情况,禁止在注释中出现 //
  • misra-c2012-5.9 : Identifiers that define objects or functions with internal linkage should be unique

    • 禁用原因:包含 static inline 内联函数的头文件多处使用时,内联函数被认为重复定义。
  • misra-c2012-8.7 : Functions and objects should not be defined with external linkage if they are referenced in only one translation unit

    • 禁用原因:XWOS提供的API并不一定被自己使用,对于 MISRA-C2012 规范的检查工具,可能会因为只检查到一次符号而报错。
  • misra-c2012-8.9 : An object should be defined at block scope if its identifier only appears in a single function

    • 禁用原因:有些数据定义为全局,是为了链接时放在特定的段。
  • misra-c2012-11.3 : A cast shall not be performed between a pointer to object type and a pointer to a different object type

    • 禁用原因
        1. XWOS中各类型的原子操作和位操作是根据位宽转换为8位、16位、32位、64位基本类型来实现的;
        1. 动态内存管理;
        1. C语言面向对象。
  • misra-c2012-11.4 : A conversion should not be performed between a pointer to object and an integer type

    • 禁用原因
        1. 在指令和寄存器级别的代码;
        1. xwcc_derof() 宏的实现;
        1. 动态内存管理;
        1. C语言面向对象。
  • misra-c2012-11.5 : A conversion should not be performed from pointer to void into pointer to object

    • 禁用原因
        1. 动态内存管理;
        1. 通讯协议协议的变长消息;
        1. 回调函数的用户参数是个泛型指针。
  • misra-c2012-11.6 : A cast shall not be performed between pointer to void and an arithmetic type

    • 禁用原因
        1. XWOS将 -1-4095 的指针值当作错误码指针。但是指针是一个无符号整数。 因此是以补码形式表示。 -10xFFFFFFFF-40950xFFFFF001
        1. 动态内存管理。
  • misra-c2012-15.1 : The goto statement should not be used

    • 禁用原因:XWOS只在下面两种情况下使用 goto
        1. XWOS内某些比较核心的算法(例如红黑树),会使用 goto 来提高效率。
        • 1.1. 因为这类代码在整个内核中被大量使用,效率是优先考虑的重点;
        • 1.2. 这类代码被验证得最充分,稳定性与安全性最高。
        1. XWOS使用 goto 来处理出错时的代码返回。
        • 2.1. 如果代码中包含了大量的操作,每个操作都有返回值,若使用 if...else... 将使得嵌套特别深。使用 goto 能使得代码更美观易读;
        • 2.2. 如果代码中包含了大量的操作,每个操作都有对应的反操作,操作与反操作需要像 “栈” 结构一样先进后出,使用 if...else... 很容易 遗漏反操作或将反操作的顺序搞错,但使用 goto 就可完美解决这一问题。
/* 如果包含大量操作,使用 `if...else...` 将使得代码行过长,
 * 并且anti_operationX() 很容易写错位置或者遗漏。
 */
int func1(void)
{
        rc = operation1();
        if (0 == rc) {
                rc = operation3();
                if (0 == rc) {
                        rc = operation8();
                        if (0 == rc) {
                                rc = operation2();
                                if (0 == rc) {
                                        rc = operation6();
                                        if (0 == rc) {
                                                rc = operation5();
                                                if (0 == rc) {
                                                } else {
                                                        anti_operation6();
                                                }
                                        } else {
                                                anti_operation2();
                                        }
                                } else {
                                        anti_operation8();
                                }
                        } else {
                                anti_operation3();
                        }
                } else {
                    anti_operation1();
                }
        } else {
        }
        return rc;
}

/* 使用 `goto` 将避免 `if...else...` 上述的两个问题。*/
int func2(void)
{
        rc = operation1();
        if (rc < 0) {
                goto err_operation1;
        }
        rc = operation3();
        if (rc < 0) {
                goto err_operation3;
        }
        rc = operation8();
        if (rc < 0) {
                goto err_operation8;
        }
        rc = operation2();
        if (rc < 0) {
                goto err_operation2;
        }
        rc = operation6();
        if (rc < 0) {
                goto err_operation6;
        }
        rc = operation5();
        if (rc < 0) {
                goto err_operation5;
        }
        return rc;

        anti_operation5();
err_operation5:
        anti_operation6();
err_operation6:
        anti_operation2();
err_operation2:
        anti_operation8();
err_operation8:
        anti_operation3();
err_operation3:
        anti_operation1();
err_operation1:
        return rc;
}
  • misra-c2012-17.1 : The features of <stdarg.h> shall not be used

    • 禁用原因:不应该完全禁止语言特性。
  • misra-c2012-18.8 : Variable-length array types shall not be used

    • 禁用原因:变长数组是C99标准引入的特性,XWOS在新版本中会偏向于引入新的语言特性。
  • misra-c2012-19.2 : The union keyword should not be used

    • 禁用原因:
      • 编写操作系统时不可避免地需要将内存地址转换为不同类型的指针,使用 union 可以避免直接对 void * 进行转换,提高可读性。
  • misra-c2012-20.9 : All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be #define ’d before evaluation

    • 禁用原因:检测工具会误报,但XWOS的代码是遵循此规则的。
  • misra-c2012-21.1 : ** #define and #undef shall not be used on a reserved identifier or reserved macro name**

    • 禁用原因:C语言将任何以 _ 开头的符号作为保留,但有些符号来自于编译器的扩展语法,例如 __attribute__((x)) ,通常将它们定义为两个 _ 开头的宏来使用, 以显示它们和正常的变量、函数、宏的区别。
  • misra-c2012-21.3 The memory allocation and deallocation functions of <stdlib.h> shall not be used

    • 禁用原因:完全禁止动态内存管理不利于引入高级语言。 仅当安全等级非常高时才禁止动态内存管理,相应的一些功能也不可被使用,例如Lua语言。
  • misra-c2012-21.6 : The Standard Library input/output functions shall not be used

    • 禁用原因: stdio.h 的函数在XWOS内被重新定义过。
  • misra-c2012-21.10 : The Standard Library time and date functions shall not be used

    • 禁用原因: time.h 的函数在XWOS内被重新定义过。

部分文件禁用的规则

  • misra-c2012-2.7 : There should be no unused parameters in functions

    • 禁用原因:此头文件中包含CPU架构指令级别的函数,这些函数使用内联汇编语法编写, 在C语法层面看起来有些参数未使用,实际上这些参数是根据 EABI 规则通过寄存器在使用。
      • 适用范围:
        • xwcd/soc/arm/v6m/armv6m_isa.h
        • xwcd/soc/arm/v7m/armv7m_isa.h
        • xwcd/soc/powerpc/e200x/e200x_isa.h
        • xwcd/soc/riscv/nuclei/riscv_isa.h
  • misra-c2012-5.7 : A tag name shall be a unique identifier

    • 禁用原因:匿名结构体被认为 tag name 重复是误报。
      • 适用范围:
        • xwcd/soc/arm/v6m/armv6m_isa.h
        • xwcd/soc/arm/v7m/armv7m_isa.h
        • xwcd/soc/powerpc/e200x/e200x_isa.h
        • xwcd/soc/riscv/nuclei/riscv_isa.h
        • xwcd/ds/uart/common.h
        • xwcd/ds/uart/controller.h
        • xwcd/ds/soc/chip.h
        • xwos/lib/xwbop.c
        • xwos/mp/skd.h
        • xwos/up/skd.h
        • xwos/mp/thd.h
        • xwos/up/thd.h
        • xwos/mp/sync/obj.h
        • xwos/up/sync/obj.h
        • xwos/mm/mempool/objcache.h
        • xwos/mm/mempool/page.h
        • xwmd/isc/xwssc/protocol.h
        • xwmd/libc/newlibac/lock.c
        • xwmd/libc/picolibac/lock.c
    • 禁用原因:libc要求定义的符号
      • 适用范围:
        • xwmd/libc/newlibac/lock.c
        • xwmd/libc/picolibac/lock.c
  • misra-c2012-5.8 : A tag name shall be a unique identifier

    • 禁用原因:结构体内部的成员名是在结构体的namespace内的,不会和外面符号发生冲突。
      • 适用范围:
        • xwmd/isc/xwssc/hwifal.h
        • xwos/mm/mempool/i_allocator.h
        • xwmd/libc/picolibcac/mem.c
        • xwos/mm/mempool/page.h
    • 禁用原因:对LIBC中的标准函数进行重写。
      • 适用范围:
        • xwmd/libc/picolibcac/fops.c
  • misra-c2012-8.4 : A compatible declaration shall be visible when an object or function with external linkage is defined

    • 禁用原因:误报
      • 适用范围:
        • xwos/ospl/xwosplcb.c
    • 禁用原因:Rust语言的 ffi 不是在C语言层面进行链接。
      • 适用范围:
        • xwmd/xwrust/ffi/*.c
  • misra-c2012-8.5 : An external object or function shall be declared once in one and only one file

    • 禁用原因: xwos/ospl/soc/*.h 是操作系统移植层的代码,对符号再次定义,起到汇总与强调的作用。提示用户移植时需要提供这些符号的定义。
      • 适用范围:
        • xwos/ospl/soc/*.h
        • xwos/lib/xwbop.h
        • xwos/lib/lfq.h
    • 禁用原因:误报
      • 适用范围
        • xwmd/libc/newlibac/*.c
        • xwmd/libc/picolibcac/*.c
  • misra-c2012-8.6 : An identifier with external linkage shall have exactly one external definition

    • 禁用原因:误报
      • 适用范围
        • xwmd/libc/newlibac/*.c
        • xwmd/libc/picolibcac/*.c
  • misra-c2012-8.14 : The restrict type qualifier shall not be used

    • 禁用原因:对LIBC中的标准函数进行重写。
      • 适用范围:
        • xwmd/libc/newlibac/string.c
        • xwmd/libc/picolibcac/string.c
        • xwmd/libc/newlibac/time.c
        • xwmd/libc/picolibcac/time.c
  • misra-c2012-9.2 : The initializer for an aggregate or union shall be enclosed in braces

    • 禁用原因:误报
      • 适用范围:
        • xwmd/libc/newlibac/fops.c
        • xwmd/libc/picolibcac/fops.c
  • misra-c2012-9.3 : Arrays shall not be partially initialized

    • 禁用原因:误报
      • 适用范围:
        • xwmd/libc/newlibac/fops.c
        • xwmd/libc/picolibcac/fops.c
  • misra-c2012-10.8 : The value of a composite expression shall not be cast to a different essential type category or a wider essential type

    • 禁用原因:宏定义的表达式是复合的表达式,不得不使用强制类型转换
      • 适用范围:
        • xwos/mm/mempool/page.c
  • misra-c2012-11.1 : Conversions shall not be performed between a pointer to a function and any other type

    • 禁用原因:操作系统抽象层到实现层的必要转换
      • 适用范围:
        • xwos/osal/thd.h
        • xwos/osal/swt.h
  • misra-c2012-12.3 : The comma operator should not be used

    • 禁用原因:XWOS的链表( xwos/lib/bclst.h )中的迭代操作宏不得不使用逗号表达式来定义。
      • 适用范围:
        • xwos/mp/skd.c
        • xwos/up/skd.c
  • misra-c2012-14.2 : A for loop shall be well-formed

    • 禁用原因:XWOS的链表( xwos/lib/bclst.h )中的迭代操作过于复杂,使用宏定义来简化代码。
      • 适用范围:
        • xwos/mp/skd.c
        • xwos/up/skd.c
  • misra-c2012-15.2 : The goto statement shall jump to a label declared later in the same function

    • 禁用原因:这部分代码是XWOS低中断延迟的关键代码,必须优先考虑实时性和性能,因此不得不用 goto 来实现。
      • 适用范围:
        • xwos/mp/tt.c
        • xwos/up/tt.c
    • 禁用原因:误报。
      • 适用范围:
        • xwmd/isc/xwssc/mif.c
  • misra-c2012-15.4 : There should be no more than one break or goto statement used to terminate any iteration statement

    • 禁用原因:这部分代码是XWOS低中断延迟的关键代码,必须优先考虑实时性和性能,因此不得不用 goto 来实现。
      • 适用范围:
        • xwos/mp/tt.c
        • xwos/up/tt.c
    • 禁用原因:使用率较高的代码只使用一个 breakgoto 影响效率。
      • 适用范围:
        • xwos/up/skd.c
        • xwos/mp/sync/evt.c
        • xwos/up/sync/evt.c
        • xwmd/isc/xwssc/hwifal.c
        • xwmd/isc/xwssc/protocol.c
  • misra-c2012-15.5 : A function should have a single point of exit at the end

    • 禁用原因:函数参数检测的代码被定义为一个宏,其中包含了一个 return
      • 适用范围:
        • xwmd/isc/xwssc/mif.c
  • misra-c2012-17.2 : Functions shall not call themselves, either directly or indirectly

    • 禁用原因:这部分代码是XWOS独创的开中断调度技术的关键代码,不得不使用递归函数来实现。此处代码被验证得非常充分,稳定性与安全性不用担心。
      • 适用范围:
        • xwos/mp/skd.c
        • xwos/up/skd.c
  • misra-c2012-17.7 : The value returned by a function having non-void return type shall be used

    • 禁用原因:C库函数 memset() , memcpy() 等有返回值,但这里并不使用它们。
      • 适用范围:
        • xwos/mp/rtrq.c
        • xwos/up/rtrq.c
        • xwos/mp/sync/evt.c
        • xwos/up/sync/evt.c
        • xwmd/isc/xwcq/xwcq.c
        • xwmd/isc/xwssc/hwifal.c
        • xwmd/isc/xwssc/mif.c
        • xwmd/isc/xwssc/protocol.c
        • xwmd/libc/newlibac/mif.c
        • xwmd/libc/picolibcac/mif.c
        • xwmd/libc/newlibac/mem.c
        • xwmd/libc/picolibcac/mem.c
    • 禁用原因:确定不使用返回值的地方,使用 cppcheck-suppress [misra-c2012-17.7] 标注。
      • 适用范围:
        • xwos/init.c
        • xwos/mp/lock/mtx.c
        • xwos/up/lock/mtx.c
        • xwos/mp/lock/spinlock.c
        • xwos/up/lock/seqlock.c
        • xwmd/isc/xwssc/mif.c
        • xwmd/isc/xwssc/protocol.c
        • xwos/mm/mempool/objcache.c
        • xwos/mm/mempool/allocator.c
        • xwos/mm/mempool/page.c
  • misra-c2012-17.8 : A function parameter should not be modified

    • 禁用原因:为了追求效率以及内存使用率,不遵循此规则。
      • 适用范围:
        • xwos/lib/xwbop.c
        • xwos/mm/bma.c
        • xwos/mm/mempool/objcache.c
        • xwos/mm/mempool/page.c
        • xwos/mm/mempool/allocator.c
        • xwos/mp/lock/mtx.c
        • xwos/up/lock/mtx.c
        • xwmd/isc/xwssc/protocol.c
        • xwmd/libc/newlibac/string.c
        • xwmd/libc/picolibcac/string.c
  • misra-c2012-20.7 : Expressions resulting from the expansion of macro parameters shall be enclosed in parentheses

    • 禁用原因:这部分代码使用宏来模拟C++的函数模板,其中作为类型名的参数不能使用括号封闭起来。
      • 适用范围:
        • xwos/lib/xwaop.h
        • xwos/lib/xwbop.h
    • 禁用原因:这部分代码使用宏来定义数组,其中作为数组名参数不能使用括号封闭起来。
      • 适用范围:
        • xwos/mm/bma.h
        • xwos/mm/mempool/allocator.h
        • xwmd/isc/xwssc/mif.h
        • xwmd/isc/xwcq/mif.h
  • misra-c2012-20.10 : The # and ## preprocessor operators should not be used

    • 禁用原因:这部分代码使用宏来模拟C++的函数模板,必须使用到 ###
      • 适用范围:
        • xwos/lib/xwaop.h
        • xwos/lib/xwbop.h
  • misra-c2012-20.12 : A macro parameter used as an operand to the # or ## operators, which is itself subject to further macro replacement, shall only be used as an operand to these operators

    • 禁用原因:这部分代码使用宏来模拟C++的函数模板。
      • 适用范围:
        • xwos/lib/xwaop.h
        • xwos/lib/xwbop.h
  • misra-c2012-21.2 A reserved identifier or macro name shall not be declared

    • 禁用原因:对LIBC中的标准函数进行重写。
      • 适用范围:
        • xwmd/libc/newlibac/string.c
        • xwmd/libc/picolibcac/string.c
        • xwmd/libc/picolibcac/fops.c
        • xwmd/libc/picolibcac/mem.c
  • misra-c2012-21.4 The standard header file <setjmp.h> shall not be used

    • 禁用原因:不应该完全禁止语言特性,XWOS对 <setjmp.h> 提供了支持 。
      • 适用范围:
        • xwmd/libc/newlibac/setjmp.c
        • xwmd/libc/picolibcac/setjmp.c