Search code examples
carmsonarqubecortex-mmisra

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?


Generic description

I encountered the following SonarQube remark (MISRA-C:2012), while implementing the startup code in C, for an ARM Cortex-M3:

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

with the following description:

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.

I am using the following compiler:

armclang V6.12, with Language C99

The version of the SonarQube is:

Version 6.7 (build 33306)


The SonarQube remark is raised on the Reference of Reset_Handler inside the Vector Table array. (see the code below)

The basic code that was scanned:

/*----------------------------------------------------------------------------
  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 */
    }
}


The basic problem

I don't really understand why it complains at that particular point, and I don't really see what am I missing:
- the function pointer is defined at the beginning pFunc
- the return type is defined as void, and also there are no parameters for the functions
- the type of the Vector Table array is "pFunc"
- both the Default_Handler, as well as the Reset_Handler match the correct prototype as defined by the function pointer

Any help would be appreciated. :)

Thank you.

Later edit

@Lundin I found the following example of non-compliant code:

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

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

Compliant code:

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

So you seem to be right. The tool thinks is a different issue.


Solution

  • The SonarQube warning is complaining that you're using the name of a function without calling it, suspecting that you meant to actually call it.

    Because a function name is automatically converted to a pointer to a function, func and &func refer to the same thing, so you can use them interchangeably.

    Since you're not attempting to call the functions but are instead putting their addresses in an array, use the address-of operator to make it explicit that you want to take the address of the function instead of calling it, along with any other function pointers.

    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 */
    };