This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 6fdc2dde412 drivers/serial: hold xmit.lock around echo in uart_readv()
6fdc2dde412 is described below
commit 6fdc2dde4121ae8ef9adf2b4d72887b73733797f
Author: yi chen <[email protected]>
AuthorDate: Fri Jul 10 06:12:11 2026 +0800
drivers/serial: hold xmit.lock around echo in uart_readv()
uart_putxmitchar() manipulates dev->xmit.head/buffer directly with
no internal locking - every other caller (uart_write()) takes
dev->xmit.lock first. uart_readv()'s ECHO handling (both the
backspace/delete erase sequence and the normal character echo)
calls uart_putxmitchar() without taking that lock, so a concurrent
uart_write() and a local echo can race on the same circular buffer
state, corrupting it.
Take dev->xmit.lock around each echo's uart_putxmitchar() calls,
matching what uart_write() already does. uart_readv() holds
dev->recv.lock for its own duration, but no other code path ever
acquires recv.lock while holding xmit.lock, so nesting xmit.lock
inside the existing recv.lock scope here doesn't introduce a new
lock-ordering cycle.
Fixes #14845
Signed-off-by: yi chen <[email protected]>
---
drivers/serial/serial.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index 5f54d972a98..da80d2e9e66 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -1031,9 +1031,11 @@ static ssize_t uart_readv(FAR struct file *filep, FAR
struct uio *uio)
recvd--;
if (dev->tc_lflag & ECHO)
{
+ nxmutex_lock(&dev->xmit.lock);
uart_putxmitchar(dev, '\b', true);
uart_putxmitchar(dev, ' ', true);
uart_putxmitchar(dev, '\b', true);
+ nxmutex_unlock(&dev->xmit.lock);
#ifdef CONFIG_SERIAL_TXDMA
uart_dmatxavail(dev);
@@ -1088,12 +1090,14 @@ static ssize_t uart_readv(FAR struct file *filep, FAR
struct uio *uio)
if (!iscntrl(ch & 0xff) || ch == '\n')
{
+ nxmutex_lock(&dev->xmit.lock);
if (ch == '\n')
{
uart_putxmitchar(dev, '\r', true);
}
uart_putxmitchar(dev, ch, true);
+ nxmutex_unlock(&dev->xmit.lock);
/* Mark the tx buffer have echoed content here,
* to avoid the tx buffer is empty such as special escape