Optimized input checks

Input validation is optimized by avoiding systematic parameter and state checks during normal operation, relying instead on debug assertions for parameters, pointers, and states.

Assertion implementation and usage in HAL1

In HAL1, the assert_param macro is used exclusively within the HAL_PPP_Init function to validate initialization parameters. Its default implementation is provided in the stm32_assert.h template file as follows:

#ifdef  USE_FULL_ASSERT
/**
  * @brief  The assert_param macro is used for function's parameters check.
  * @param  expr If expr is false, it calls assert_failed function
  *         which reports the name of the source file and the source
  *         line number of the call that failed.
  *         If expr is true, it returns no value.
  * @retval None
  */

#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))

/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t *file, uint32_t line);

#else

#define assert_param(expr) ((void)0U)

#endif /* USE_FULL_ASSERT */

To activate the assertion:

  • Add the USE_FULL_ASSERT compilation switch to the IDE preprocessor settings.

  • Implement the assert_failed function.

Several HAL1 examples provide the following implementation of the assert_failed function:

void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add their own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
  /* USER CODE END 6 */
}

Additionally, state validity checks in HAL1 APIs are performed at runtime, as demonstrated below:

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
{
...
  /* Check that a Tx process is not already ongoing */
  if (huart->gState == HAL_UART_STATE_READY)
  {
    huart->gState = HAL_UART_STATE_BUSY_TX;
    ..
  }
}

Assertion implementation and usage in HAL2

In HAL2, all HAL APIs validate input parameters using the ASSERT_DBG_PARAM macro, extending beyond just the Init or Config functions. Additionally, HAL2 APIs verify the validity of the current state for operations, such as configuration, feature setting, and processes, through assertions using the ASSERT_DBG_STATE macro.

The code snippet below shows an example of the use of the ASSERT_DBG_PARAM and ASSERT_DBG_STATE macros.

hal_status_t HAL_UART_Transmit_DMA(hal_uart_handle_t *huart, const void *p_data, uint32_t size_byte)
{
  ASSERT_DBG_PARAM(huart != NULL);
  ASSERT_DBG_PARAM(p_data != NULL);
  ASSERT_DBG_PARAM(size_byte != 0);
  ASSERT_DBG_PARAM(huart->hdma_tx != NULL);

  ASSERT_DBG_STATE(huart->global_state, HAL_UART_STATE_CONFIGURED);
  ASSERT_DBG_STATE(huart->tx_state, HAL_UART_TX_STATE_IDLE);
  ..
}

The stm32_assert.h template file provides a default implementation of the ASSERT_DBG_PARAM and ASSERT_DBG_STATE macros, as shown below:

#if defined(USE_ASSERT_DBG_PARAM)

/**
  * @brief  The ASSERT_DBG_PARAM macro is used for function's parameters check.
  * @param  expr If expr is false, it calls assert_dbg_param_failed function
  *         which reports the name of the source file and the source
  *         line number of the call that failed.
  *         If expr is true, it returns no value.
  * @retval None
  */

#define ASSERT_DBG_PARAM(expr) ((expr) ? (void)0U : assert_dbg_param_failed((uint8_t *)__FILE__, __LINE__))

/* Exported functions ------------------------------------------------------- */
void assert_dbg_param_failed(uint8_t *file, uint32_t line);

#else

#define ASSERT_DBG_PARAM(expr) ((void)0U)

#endif /* USE_ASSERT_DBG_PARAM */
#if defined(USE_ASSERT_DBG_STATE)
/**
  * @brief  The ASSERT_DBG_STATE macro is used for function's states check.
  * @param  __STATE__ the state field within the PPP handle
  * @param  __VAL__ the authorized states value(s) to be checked
  *                 can be a combination of states
  * @note   if __STATE__ & __VAL__ is zero (unauthorized state) then
  * @note   assert_dbg_state_failed function is called which reports
  *         the name of the source file and the source line number of the call that failed.
  *         if __STATE__ & __VAL__ is zero (unauthorized state) then, the ASSERT_DBG_STATE macro returns no value.
  */

#define ASSERT_DBG_STATE(__STATE__,__VAL__) (((((uint32_t)(__STATE__)) &  ((uint32_t)(__VAL__))) != 0U) ?  \
                                             (void)0U :                                                    \
                                             assert_dbg_state_failed((uint8_t *)__FILE__, __LINE__))

/* Exported functions ------------------------------------------------------- */
void assert_dbg_state_failed(uint8_t *file, uint32_t line);

#else

#define ASSERT_DBG_STATE(__STATE__,__VAL__) ((void)0U)

#endif /* USE_ASSERT_DBG_STATE  */

To activate the assertion:

  • Add the USE_ASSERT_DBG_PARAM compilation switch to the IDE pre-processor settings to activate assertion on parameters. In this case, provide an implementation of the assert_dbg_param_failed function as per HAL1.

  • Add the USE_ASSERT_DBG_STATE compilation switch to the IDE pre-processor settings to activate assertion on states. In this case, provide an implementation of the assert_dbg_state_failed function, similar to assert_dbg_param_failed.

Summary

Assertion implementation in HAL1 and HAL2

Aspect

HAL1

HAL2

Macro for parameter check

assert_param

ASSERT_DBG_PARAM

Macro for state check

Unavailable

ASSERT_DBG_STATE

Scope of parameter check

Used exclusively within HAL_PPP_Init functions.

Used in all HAL APIs.

Scope of state check

State validity checks done at runtime within specific functions.

State validity checks are performed using ASSERT_DBG_STATE in all HAL APIs, except for HAL_PPP_Init and HAL_PPP_Deinit, which serve as the entry and exit points to the HAL peripheral driver state machine.

Default implementation Ffile

stm32_assert.h template

stm32_assert.h template

Default implementation for assertion parameter macros

#ifdef  USE_FULL_ASSERT
#define assert_param(expr) ((expr) ? \
(void)0U : \
assert_failed((uint8_t *)__FILE__, __LINE__))

void assert_failed(uint8_t *file, uint32_t line);

#else

#define assert_param(expr) ((void)0U)

#endif /* USE_FULL_ASSERT */
#if defined(USE_ASSERT_DBG_PARAM)
#define ASSERT_DBG_PARAM(expr) ((expr) ? \
(void)0U : \
assert_dbg_param_failed((uint8_t *)__FILE__, __LINE__))

void assert_dbg_param_failed(uint8_t *file, uint32_t line);

#else

#define ASSERT_DBG_PARAM(expr) ((void)0U)

#endif /* USE_ASSERT_DBG_PARAM */

Default implementation for assertion state macros

Unavailable

#if defined(USE_ASSERT_DBG_STATE)
#define ASSERT_DBG_STATE(__STATE__,__VAL__) \
(((((uint32_t)(__STATE__)) &  ((uint32_t)(__VAL__))) != 0U) ? \
(void)0U :
assert_dbg_state_failed((uint8_t *)__FILE__, __LINE__))

void assert_dbg_state_failed(uint8_t *file, uint32_t line);

#else

#define ASSERT_DBG_STATE(__STATE__,__VAL__) ((void)0U)

#endif /* USE_ASSERT_DBG_STATE */

Assertion activation

Add USE_FULL_ASSERT to IDE pre-processor settings.

Add USE_ASSERT_DBG_PARAM and/or USE_ASSERT_DBG_STATE to IDE pre-processor settings.

Implementation of failed user application function

User provides assert_failed function implementation.

User provides assert_dbg_param_failed and/or assert_dbg_state_failed function implementation.

Example of HAL checks

HAL_StatusTypeDef HAL_UART_Transmit_DMA(
                    UART_HandleTypeDef *huart,
                    const uint8_t *pData,
                    uint16_t Size)
{
  if (huart->gState == HAL_UART_STATE_READY)
  {
    huart->gState = HAL_UART_STATE_BUSY_TX;
    /..
  }
}
hal_status_t HAL_UART_Transmit_DMA(
                   hal_uart_handle_t *huart,
                   const void *p_data,
                   uint32_t size_byte) {
  ASSERT_DBG_PARAM(huart != NULL);
  ASSERT_DBG_PARAM(p_data != NULL);
  ASSERT_DBG_PARAM(size_byte != 0);
  ASSERT_DBG_PARAM(huart->hdma_tx != NULL);

  ASSERT_DBG_STATE(huart->global_state, HAL_UART_STATE_CONFIGURED);
  ASSERT_DBG_STATE(huart->tx_state, HAL_UART_TX_STATE_IDLE);
  ..
}