Skip to content

USARTv1/v2: add osalDbgAssert for speed == 0 in usart_init#73

Open
vlordier wants to merge 1 commit into
ChibiOS:masterfrom
vlordier:fix/usart-speed-zero-assert
Open

USARTv1/v2: add osalDbgAssert for speed == 0 in usart_init#73
vlordier wants to merge 1 commit into
ChibiOS:masterfrom
vlordier:fix/usart-speed-zero-assert

Conversation

@vlordier

Copy link
Copy Markdown

Problem

In both USARTv1/hal_serial_lld.c and USARTv2/hal_serial_lld.c, the usart_init() function divides by config->speed to compute the BRR register without first checking it is non-zero:

/* USARTv1 */
brr = (uint32_t)((sdp->clock + config->speed/2) / config->speed);

/* USARTv2 standard path */
brr = (uint32_t)((clock + config->speed / 2) / config->speed);

/* USARTv2 LPUART1 path */
brr = (uint32_t)(((uint64_t)clock * 256 + config->speed/2) / config->speed);

Passing speed = 0 triggers integer division-by-zero, which is undefined behaviour in C (ISO C11 §6.5.5 ¶5). Depending on CPU and toolchain this may: cause a HardFault trap, return garbage leaving the USART misconfigured, or be silently optimised away.

The USARTv2 LPUART path is additionally affected through the range check clock >= config->speed * 3U: when speed = 0, the multiplication evaluates to 0 and the assert passes vacuously, not catching the error.

This was identified while building Rust safety wrappers for ChibiOS peripherals and writing parity tests comparing C driver behaviour against the Rust implementation.

Fix

Add osalDbgAssert(config->speed != 0U, "invalid baud rate (zero)") at the top of the baud-rate calculation section, before any arithmetic on config->speed. Placement and style are identical to the existing BRR range validation:

osalDbgAssert(brr < 0x10000, "invalid BRR value");

Notes

  • Debug-only: osalDbgAssert compiles away in release builds. A release build with speed = 0 continues to have undefined behaviour; this is consistent with how ChibiOS handles other parameter preconditions.
  • hal_uart_lld.c is not included in this patch: the UART HAL driver does not use config->speed directly for BRR; baud rate comes from the SerialConfig passed to the serial driver. A separate audit of hal_uart_lld.c may be warranted.
  • No API change.

In both USARTv1 and USARTv2 hal_serial_lld.c, usart_init() divides
by config->speed to compute the BRR register value without first
checking that speed is non-zero:

  USARTv1: brr = (sdp->clock + config->speed/2) / config->speed;
  USARTv2: brr = (clock + config->speed / 2) / config->speed;
  USARTv2 LPUART: brr = (clock * 256 + config->speed/2) / config->speed;

Passing speed = 0 triggers integer division-by-zero, which is
undefined behaviour in C. Depending on the CPU and toolchain, this
may cause a hard fault, return garbage, or be silently optimised
away, leaving the USART misconfigured.

Both files already use osalDbgAssert() to validate the computed BRR
range (e.g. "invalid BRR value"); this patch adds a matching check
at the entry of the baud-rate calculation section, before any
arithmetic on config->speed occurs.

The fix is debug-only (osalDbgAssert), consistent with ChibiOS
convention. A release build continues to exhibit undefined behaviour
when speed = 0, but that is an existing driver contract; the assert
gives developers an actionable trap during development.
Copilot AI review requested due to automatic review settings April 18, 2026 15:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a debug-time precondition check to STM32 USART low-level serial drivers to prevent undefined behavior (division by zero) when SerialConfig.speed is accidentally set to 0.

Changes:

  • Add osalDbgAssert(config->speed != 0U, "invalid baud rate (zero)") at the start of baud-rate/BRR computation in USARTv1.
  • Add the same assert at the start of baud-rate/BRR computation in USARTv2 (including the LPUART path).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
os/hal/ports/STM32/LLD/USARTv2/hal_serial_lld.c Adds debug assert guarding config->speed before BRR arithmetic to avoid divide-by-zero UB.
os/hal/ports/STM32/LLD/USARTv1/hal_serial_lld.c Adds debug assert guarding config->speed before BRR arithmetic to avoid divide-by-zero UB.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants