drivers/serial: fix crash when buffer is full and only recvbuf is implemented

When the receive buffer is full and the driver only implements recvbuf
operation without receive operation, the code would crash due to calling
a NULL function pointer. This patch fixes the issue by:

1. Check if recvbuf is available before calling it
2. When buffer is full, use a temporary buffer to drain hardware FIFO
   to prevent data accumulation in hardware
3. Add proper NULL check for receive operation to avoid crash
4. Initialize pbuf to NULL to prevent uninitialized variable usage

This ensures the serial driver works correctly even when only recvbuf
is implemented and the receive buffer is full.

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu1
2025-08-29 16:29:44 +08:00
committed by Xiang Xiao
parent c7bb7ece8e
commit 1946bc4e44
+37 -23
View File
@@ -166,7 +166,7 @@ void uart_recvchars(FAR uart_dev_t *dev)
{
int nexthead = rxbuf->head + 1 < rxbuf->size ? rxbuf->head + 1 : 0;
bool is_full = (nexthead == rxbuf->tail);
FAR char *pbuf;
FAR char *pbuf = NULL;
char ch;
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
@@ -217,38 +217,52 @@ void uart_recvchars(FAR uart_dev_t *dev)
/* Get this next character from the hardware */
if (!is_full && dev->ops->recvbuf)
if (dev->ops->recvbuf)
{
ssize_t ret;
if (rxbuf->tail > rxbuf->head)
if (!is_full)
{
nbytes = rxbuf->tail - rxbuf->head - 1;
}
else if (rxbuf->tail)
{
nbytes = rxbuf->size - rxbuf->head;
if (rxbuf->tail > rxbuf->head)
{
nbytes = rxbuf->tail - rxbuf->head - 1;
}
else if (rxbuf->tail)
{
nbytes = rxbuf->size - rxbuf->head;
}
else
{
nbytes = rxbuf->size - rxbuf->head - 1;
}
pbuf = &rxbuf->buffer[rxbuf->head];
ret = uart_recvbuf(dev, pbuf, nbytes);
if (ret <= 0)
{
continue;
}
nbytes = ret;
rxbuf->head += nbytes;
if (rxbuf->head >= rxbuf->size)
{
rxbuf->head = 0;
}
}
else
{
nbytes = rxbuf->size - rxbuf->head - 1;
}
pbuf = &ch;
nbytes = 1;
pbuf = &rxbuf->buffer[rxbuf->head];
ret = uart_recvbuf(dev, pbuf, nbytes);
if (ret <= 0)
{
continue;
}
nbytes = ret;
rxbuf->head += nbytes;
if (rxbuf->head >= rxbuf->size)
{
rxbuf->head = 0;
ret = uart_recvbuf(dev, pbuf, nbytes);
if (ret <= 0)
{
continue;
}
}
}
else
else if(dev->ops->receive)
{
unsigned int status;