Skip to content

fix(Serial): Uart::write() must not spin when begin() failed - #3074

Merged
fpistm merged 1 commit into
stm32duino:mainfrom
saikumar-mandaji:fix-uart-write-deadlock-when-not-ready
Sep 8, 2026
Merged

fix(Serial): Uart::write() must not spin when begin() failed#3074
fpistm merged 1 commit into
stm32duino:mainfrom
saikumar-mandaji:fix-uart-write-deadlock-when-not-ready

Conversation

@saikumar-mandaji

Copy link
Copy Markdown
Contributor

Bug

If Serial.begin(baud) fails during hardware init (e.g. an LPUART clocked from LSE can't reach the requested baud rate), uart_init() returns false and _ready is set to false — but Uart::write() never checks _ready before entering its transmit path.

Uart::write(const uint8_t*, size_t) contains:

while (!availableForWrite()) {
    // nop, the interrupt handler will free up space for us
}

Since the hardware was never actually brought up, the TX interrupt this loop waits on never fires, so once the 63-byte TX ring buffer fills up (a few Serial.print() calls after a failed begin()), this spins forever and the MCU deadlocks permanently. See #3071 for the full repro (STM32WLE5 LPUART1 on LSE, GPS driver baud-probing 9600 -> 38400 -> deadlock).

Fix

Return 0 immediately if !_ready, before touching the buffer or entering the wait loop — this is exactly the guard suggested in #3071. write(uint8_t) needs no separate guard since it already delegates to this overload.

Verification

  • No hardware was available to reproduce the deadlock physically.
  • I attempted a real compile check with arm-none-eabi-g++ -fsyntax-only against the actual STM32WLxx variant/CMSIS/HAL headers in this repo, but this checkout is missing the CMSIS-Core headers (core_cm4.h etc.) that a full Arduino IDE/arduino-cli install would normally fetch separately — they aren't vendored in the git tree itself, so a from-scratch clone can't be fully compiled without that tooling. I'm disclosing this honestly rather than claiming a green compile I didn't actually get.
  • The change itself is a minimal, single early-return guard using the pre-existing _ready member (already set in Uart::begin() and already exposed via an accessor in Serial.h, both in the same file/class), so the risk profile is low even without a full build.

Fixes #3071

@fpistm fpistm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hi @saikumar-mandaji
Thanks for the PR. Makes sense.
Only one comment to address.

Comment thread cores/arduino/Serial.cpp Outdated
If Serial.begin(baud) fails during hardware init (e.g. an LPUART
clocked from LSE can't reach the requested baud rate), uart_init()
returns false and _ready is set to false -- but Uart::write() never
checks _ready before entering its transmit path.

Uart::write(const uint8_t*, size_t) contains:

    while (!availableForWrite()) {
        // nop, the interrupt handler will free up space for us
    }

Since the hardware was never actually brought up, the TX interrupt
this loop waits on never fires, so once the 63-byte TX ring buffer
fills up (a few Serial.print() calls after a failed begin()), this
spins forever and the MCU deadlocks permanently.

Fix: return 0 immediately if !_ready, before touching the buffer or
entering the wait loop, using the same _ready accessor already used
elsewhere in this file (see Uart::begin(), which sets it, and the
existing operator bool()-style accessor in Serial.h). write(uint8_t)
needs no separate guard since it already delegates to this overload.

Fixes stm32duino#3071
@fpistm
fpistm force-pushed the fix-uart-write-deadlock-when-not-ready branch from 41e8ca7 to 955c68b Compare September 8, 2026 08:55
@fpistm fpistm added the fix 🩹 Bug fix label Sep 8, 2026
@fpistm fpistm added this to the 3.0.1/3.1.0 milestone Sep 8, 2026
@github-project-automation github-project-automation Bot moved this from In progress to Reviewer approved in STM32 core based on ST HAL Sep 8, 2026
@fpistm
fpistm merged commit 2420b31 into stm32duino:main Sep 8, 2026
29 checks passed
@github-project-automation github-project-automation Bot moved this from Reviewer approved to Done in STM32 core based on ST HAL Sep 8, 2026
@t-miura

t-miura commented Sep 8, 2026

Copy link
Copy Markdown

Thank you so much for the fix, I will test with Meshtastic very soon!

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

Labels

fix 🩹 Bug fix

Projects

Development

Successfully merging this pull request may close these issues.

[bug] Uart::write() deadlocks when Serial.begin() fails (LPUART with unsupported baud/clock)

3 participants