为什么 SonarQube 会对 ARM Cortex-M3 的 "startup" 代码提出 MISRA-C 批评意见 <<Function names should be used either as a call [...]>>?

Why does SonarQube raise a MISRA-C critical remark <<Function names should be used either as a call [...]>> on the "startup" code for ARM Cortex-M3?

一般描述

我在用 C 语言为 ARM Cortex-M3 实现启动代码时遇到了以下 SonarQube 评论 (MISRA-C:2012):

Function names should be used either as a call with a parameter list or with the "&" operator

具有以下描述:

Using a "bald" function name is likely a bug. Rather than testing the return value of a function with a void parameter list, it implicitly retrieves the address of that function in memory. If that's truly what's intended, then it should be made explicit with the use of the & (address-of) operator. If it's not, then a parameter list (even an empty one) should be added after the function name.

我正在使用以下编译器:

armclang V6.12, with Language C99

SonarQube 的版本是:

Version 6.7 (build 33306)


SonarQube 评论是在 Vector Table 数组内的 Reset_Handler 的引用上提出的。 (见下方代码)

扫描到的基本码:

/*----------------------------------------------------------------------------
  Exception / Interrupt Handler Function Prototype
 *----------------------------------------------------------------------------*/
typedef void (*pFunc)(void);

/*----------------------------------------------------------------------------
  External References
 *----------------------------------------------------------------------------*/
extern uint32_t __INITIAL_SP;

extern __NO_RETURN void __PROGRAM_START(void);

/*----------------------------------------------------------------------------
  Internal References
 *----------------------------------------------------------------------------*/
__NO_RETURN void Default_Handler(void);
__NO_RETURN void Reset_Handler(void);

/*----------------------------------------------------------------------------
  Exception / Interrupt Handler
 *----------------------------------------------------------------------------*/
/* Exceptions */
void NMI_Handler            (void) __attribute__ ((weak, alias("Default_Handler")));
void HardFault_Handler      (void) __attribute__ ((weak, alias("Default_Handler")));
void MemManage_Handler      (void) __attribute__ ((weak, alias("Default_Handler")));
void BusFault_Handler       (void) __attribute__ ((weak, alias("Default_Handler")));
void UsageFault_Handler     (void) __attribute__ ((weak, alias("Default_Handler")));
void SVC_Handler            (void) __attribute__ ((weak, alias("Default_Handler")));
void DebugMon_Handler       (void) __attribute__ ((weak, alias("Default_Handler")));
void PendSV_Handler         (void) __attribute__ ((weak, alias("Default_Handler")));
void SysTick_Handler        (void) __attribute__ ((weak, alias("Default_Handler")));
/*----------------------------------------------------------------------------
  Exception / Interrupt Vector table
 *----------------------------------------------------------------------------*/

extern const pFunc __VECTOR_TABLE[16];
       const pFunc __VECTOR_TABLE[16] __VECTOR_TABLE_ATTRIBUTE = {
  (pFunc)(&__INITIAL_SP),                   /*     Initial Stack Pointer */
  Reset_Handler,                            /*     Reset Handler <<<<<------ WHERE THE SONARQUBE REMARK IS */
  NMI_Handler,                              /* -14 NMI Handler */
  HardFault_Handler,                        /* -13 Hard Fault Handler */
  MemManage_Handler,                        /* -12 MPU Fault Handler */
  BusFault_Handler,                         /* -11 Bus Fault Handler */
  UsageFault_Handler,                       /* -10 Usage Fault Handler */
  0,                                        /*     Reserved */
  0,                                        /*     Reserved */
  0,                                        /*     Reserved */
  0,                                        /*     Reserved */
  SVC_Handler,                              /*  -5 SVCall Handler */
  DebugMon_Handler,                         /*  -4 Debug Monitor Handler */
  0,                                        /*     Reserved */
  PendSV_Handler,                           /*  -2 PendSV Handler */
  SysTick_Handler,                          /*  -1 SysTick Handler */
};

void Reset_Handler(void)
{
    SystemInit(); // CMSIS System Initialization
    __PROGRAM_START(); // Enter PreMain (C library entry point)
}

void Default_Handler(void)
{
    while (1) {
        __asm volatile(""); /* this line is considered to have side-effects */
    }
}


基本问题

我真的不明白为什么它会在那个特定的点抱怨,我真的不明白我错过了什么:
-函数指针定义在开头pFunc
- return 类型定义为 void,并且函数
也没有参数 - Vector Table 数组的类型是 "pFunc"
- Default_HandlerReset_Handler 都匹配函数指针定义的正确原型

如有任何帮助,我们将不胜感激。 :)

谢谢。

稍后编辑

@Lundin 我发现了以下不合规代码的示例:

int func(void) {
  // ...
}

void f2(int a, int b) {
  // ...
  if (func) {  // Noncompliant - tests that the memory address of func() is non-null
    //...
  }
  // ...
}  

合规代码:

void f2(int a, int b) {
  // ...
  if (func()) {  // tests that the return value of func() > 0
    //...
  }
  // ...
}

看来你是对的。该工具认为是另一个问题。

SonarQube 警告是在抱怨您在没有调用它的情况下使用函数的名称,怀疑您实际上打算调用它。

因为函数名会自动转换为指向函数的指针,所以func&func指的是同一个东西,所以可以互换使用。

由于您不是在尝试调用函数而是将它们的地址放入数组中,因此请使用地址运算符明确表示您想要获取函数的地址而不是调用它,以及任何其他函数指针。

extern const pFunc __VECTOR_TABLE[16];
       const pFunc __VECTOR_TABLE[16] __VECTOR_TABLE_ATTRIBUTE = {
  (pFunc)(&__INITIAL_SP),                    /*     Initial Stack Pointer */
  &Reset_Handler,                            /*     Reset Handler */
  &NMI_Handler,                              /* -14 NMI Handler */
  &HardFault_Handler,                        /* -13 Hard Fault Handler */
  &MemManage_Handler,                        /* -12 MPU Fault Handler */
  &BusFault_Handler,                         /* -11 Bus Fault Handler */
  &UsageFault_Handler,                       /* -10 Usage Fault Handler */
  NULL,                                      /*     Reserved */
  NULL,                                       /*     Reserved */
  NULL,                                      /*     Reserved */
  NULL,                                      /*     Reserved */
  &SVC_Handler,                              /*  -5 SVCall Handler */
  &DebugMon_Handler,                         /*  -4 Debug Monitor Handler */
  NULL,                                      /*     Reserved */
  &PendSV_Handler,                           /*  -2 PendSV Handler */
  &SysTick_Handler,                          /*  -1 SysTick Handler */
};