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.