This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch releases/13.0
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/releases/13.0 by this push:
     new db90bd8c4bf drivers/serial: hold xmit.lock around echo in uart_readv()
db90bd8c4bf is described below

commit db90bd8c4bf1a0b33c9aa1c00bed1fd9173657c4
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 a30fdcaa2fe..9cde32a1743 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

Reply via email to