Skip to main content
Visitor II
July 16, 2026
Solved

stm32f7xx_ll_gpio.h – shift-count-overflow UB detected by GCC -fanalyzer in LL_GPIO_GetPinMode / LL_GPIO_SetPinMode and related functions

  • July 16, 2026
  • 1 reply
  • 60 views

Hi,

 

**Environment**
- STM32F7xx LL Driver (STM32F7xx_HAL_Driver)
- GCC arm-none-eabi 15.2 (also reproducible with GCC ≥ 12)
- Compiler flag: `-fanalyzer`
- File: `STM32F7xx_HAL_Driver/Inc/stm32f7xx_ll_gpio.h`

---

**Problem**

When building with `-fanalyzer`, GCC reports the following warning for several inline functions in stm32f7xx_ll_gpio.h:

```
warning: shift by count ('64') >= precision of type ('32')
         [-Wanalyzer-shift-count-overflow]
```

**Root cause**

`POSITION_VAL(VAL)` is defined as `__CLZ(__RBIT(VAL))`. When the analyzer considers `Pin = 0` as a possible runtime value (which it cannot rule out without additional constraints), then:

- `__RBIT(0)` → `0`
- `__CLZ(0)` → `32` (implementation-defined, GCC arm-none-eabi returns 32)
- `32 * 2U` → `64` → shift of a `uint32_t` by 64 = **undefined behavior** per C11 §6.5.7

The affected functions all follow the same pattern:

// e.g. LL_GPIO_GetPinMode (line 307–311)
return (uint32_t)(READ_BIT(GPIOx->MODER,
    (GPIO_MODER_MODER0 << (POSITION_VAL(Pin) * 2U)))
    >> (POSITION_VAL(Pin) * 2U));

Additionally, `POSITION_VAL(Pin)` is evaluated **twice**, which is redundant.

**Affected functions** (non-exhaustive):
- `LL_GPIO_SetPinMode`
- `LL_GPIO_GetPinMode`
- `LL_GPIO_SetPinSpeed`
- `LL_GPIO_GetPinSpeed`
- `LL_GPIO_SetPinPull`
- `LL_GPIO_GetPinPull`

---

**Proposed fix**

Introduce a local `pos` variable and mask the shift count to a maximum of 30 (`Pin` 15 → bit 15 → `POSITION_VAL` = 15 → `15 * 2 = 30`). This eliminates the UB and the double evaluation:

// Before
__STATIC_INLINE uint32_t LL_GPIO_GetPinMode(GPIO_TypeDef *GPIOx, uint32_t Pin)
{
return (uint32_t)(READ_BIT(GPIOx->MODER,
(GPIO_MODER_MODER0 << (POSITION_VAL(Pin) * 2U)))
>> (POSITION_VAL(Pin) * 2U));
}

// After
__STATIC_INLINE uint32_t LL_GPIO_GetPinMode(GPIO_TypeDef *GPIOx, uint32_t Pin)
{
uint32_t pos = (POSITION_VAL(Pin) & 0xFU) * 2U; /* Pin 0..15 → shift 0..30 */
return (uint32_t)(READ_BIT(GPIOx->MODER, (GPIO_MODER_MODER0 << pos)) >> pos);
}

 

The same pattern should be applied to all other affected functions. The `& 0xFU` mask clamps the pin index to 15, making the maximum shift 30, which is always within the 32-bit precision. The mask has no effect on valid `LL_GPIO_PIN_x` inputs and adds no runtime overhead (compiler optimizes it away for constant pins).

The same class of issue likely exists in the STM32F4xx, STM32H7xx, STM32L4xx and other series LL GPIO headers.

---

 

Best regards,

André

Best answer by TDK

pin=0 is an invalid parameter. LL was designed specifically not to check for invalid parameters (unlike HAL) in order to optimize for speed. Adding the & 0xF0 operation is slower unless both 1) the compiler inlines the code and 2) optimization levels are set to nonzero. Those aren’t guarantees.

 

It’s on the user to pass valid parameters. Invalid parameters lead to invalid or undefined results--that is expected. There is no problem to solve here.

 

> compiler optimizes it away for constant pins

The compiler will also optimize out the double-evaluation on any non-zero optimization level. Though I tend to agree it should be a separate evaluation as you’ve shown it.

1 reply

TDK
TDKBest answer
July 16, 2026

pin=0 is an invalid parameter. LL was designed specifically not to check for invalid parameters (unlike HAL) in order to optimize for speed. Adding the & 0xF0 operation is slower unless both 1) the compiler inlines the code and 2) optimization levels are set to nonzero. Those aren’t guarantees.

 

It’s on the user to pass valid parameters. Invalid parameters lead to invalid or undefined results--that is expected. There is no problem to solve here.

 

> compiler optimizes it away for constant pins

The compiler will also optimize out the double-evaluation on any non-zero optimization level. Though I tend to agree it should be a separate evaluation as you’ve shown it.

"If you feel a post has answered your question, please click ""Accept as Solution""."