Blockstream / Blockstream/Jade
Possible infinite busy-loop in serial writer if the transport reports 0 bytes written repeatedly
- Dominant language
- C
- Stars
- 496
- Forks
- 127
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
`write_serial()` (`main/serial.c:150-174`) loops until all bytes are written, but only treats a return of `-1` as an error:
```c
int written = 0;
while (written != length) {
const int wrote = tinyusb_cdcacm_write_queue(TINYUSB_CDC_ACM_0, msg + written, length - written);
// or on ESP32: uart_write_bytes(UART_NUM_0, msg + written, length - written);
if (wrote == -1) {
return false;
}
written += wrote;
}
```
If the transport returns `0` repeatedly — e.g. `tinyusb_cdcacm_write_queue()` when the USB-CDC TX buffer is full and no host is reading (cable unplugged, or host app killed mid-transfer), or `uart_write_bytes()` with a full TX ring buffer — the loop spins forever with no delay and no timeout, causing the task watchdog to fire (device reboot) or a permanent hang. Note the `fwrite()` path (USB-JTAG serial on ESP32-S3) never returns `-1`, so any short write/error there already spins forever today.
`write_ble()` (`main/ble/ble.c:308-334`) has the correct pattern: bounded retries (~2s) then return `false`. And `jade_process_get_out_message()` (`main/process.c:467-469`) documents that a failed write drops the message (the host times out and retries), so returning `false` is safe and recoverable.
## Suggested fix
Mirror the BLE approach in `write_serial()`: retry with a bounded timeout (with a small delay between attempts), then return `false` after e.g. ~2s of consecutive zero-writes. The success path (`wrote > 0`) is unchanged; the only behavior change is on a stuck link, where dropping the message (host retry) replaces a watchdog reboot.
## Verification
Confirmed still present on current `master` (as of 2026-08-04): `main/serial.c:156` unchanged. The exact trigger needs hardware confirmation of the driver return value (0 vs -1) when the device is disconnected mid-write.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.