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 236b47dd019 arch/xtensa/esp32s3: Don't overrun buffers in SPI poll 
exchange.
236b47dd019 is described below

commit 236b47dd01916b433ba3eb52c7881116dc49b867
Author: Max Kriegleder <[email protected]>
AuthorDate: Fri Oct 23 02:16:45 2026 +0200

    arch/xtensa/esp32s3: Don't overrun buffers in SPI poll exchange.
    
    esp32s3_spi_poll_exchange() moves data to and from the W0-W15 registers
    one 32-bit word at a time, always copying a full word. When the transfer
    length is not a multiple of 4, the last copy reads up to 3 bytes past the
    end of txbuffer and writes up to 3 bytes past the end of rxbuffer,
    silently corrupting whatever follows the receive buffer in memory.
    
    Copy only the bytes that remain in the final partial word. Full-word
    transfers are unchanged.
    
    Found on an ESP32-S3 board with a Qorvo DW3000 UWB transceiver, SPI DMA
    disabled: 125-byte frame reads (64 + 61 bytes per chunk) corrupted the
    field following the receive buffer. The fix has been running on a
    network of these boards since and the corruption is gone.
    
    Assisted-by: Claude:claude-opus-5-5
    Signed-off-by: Max Kriegleder <[email protected]>
---
 arch/xtensa/src/esp32s3/esp32s3_spi.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/arch/xtensa/src/esp32s3/esp32s3_spi.c 
b/arch/xtensa/src/esp32s3/esp32s3_spi.c
index 8482b59aa0a..6b02b40bd7b 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_spi.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_spi.c
@@ -1117,12 +1117,15 @@ static void esp32s3_spi_poll_exchange(struct 
esp32s3_spi_priv_s *priv,
       for (int i = 0 ; i < transfer_size; i += sizeof(uintptr_t))
         {
           uint32_t w_wd = UINT32_MAX;
+          size_t chunk = MIN(sizeof(uint32_t), transfer_size - i);
 
           if (tp != NULL)
             {
-              memcpy(&w_wd, tp, sizeof(uintptr_t));
+              /* The last word may be partial: never read past txbuffer */
 
-              tp += sizeof(uintptr_t);
+              memcpy(&w_wd, tp, chunk);
+
+              tp += chunk;
             }
 
           putreg32(w_wd, data_buf_reg);
@@ -1184,13 +1187,16 @@ static void esp32s3_spi_poll_exchange(struct 
esp32s3_spi_priv_s *priv,
           for (int i = 0 ; i < transfer_size; i += sizeof(uintptr_t))
             {
               uint32_t r_wd = getreg32(data_buf_reg);
+              size_t chunk = MIN(sizeof(uint32_t), transfer_size - i);
 
               spiinfo("recv=0x%" PRIx32 " data_reg=0x%" PRIxPTR "\n",
                       r_wd, data_buf_reg);
 
-              memcpy(rp, &r_wd, sizeof(uintptr_t));
+              /* The last word may be partial: never write past rxbuffer */
+
+              memcpy(rp, &r_wd, chunk);
 
-              rp += sizeof(uintptr_t);
+              rp += chunk;
 
               /* Update data_buf_reg to point to the next data buffer
                * register.

Reply via email to